mybatis中#與$的使用區(qū)別

關(guān)鍵詞,預(yù)編譯,防sql注入,動(dòng)態(tài)sql

????我們?cè)谑褂胢ybatis中編寫sql語句的時(shí)候,經(jīng)常會(huì)使用#或者$來取值,也會(huì)在一條sql中同時(shí)使用。兩者的區(qū)別是什么呢??

? ? 首先在搞清楚兩者區(qū)別之前,我們先了解一下什么是預(yù)編譯。

? ? ? 在https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html 文檔中關(guān)于PreparedStatement 部分有這么一句描述? Two variants of prepared statements are implemented by Connector/J, the client-side and the server-side prepared statements 。指出有兩種預(yù)編譯 客戶端預(yù)編譯和服務(wù)端預(yù)編譯,客戶端主要指jdbc驅(qū)動(dòng),服務(wù)端指mysql。

????已知的MySQL Server 4.1之前的版本是不支持預(yù)編譯的, 參考博文1,對(duì)預(yù)編譯默認(rèn)是否開啟做了探索,得出結(jié)論 是否開啟跟具體的驅(qū)動(dòng)版本有關(guān)系。本文在官網(wǎng)https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.htmlhttps://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html 看到的關(guān)于useServerPrepStmts的描述都是Default: false。

開啟服務(wù)端預(yù)編譯的關(guān)鍵參數(shù):

1.開啟服務(wù)端預(yù)編譯的全局參數(shù) useServerPrepStmts=true,默認(rèn)是不開啟的,官方描述 Use server-side prepared statements if the server supports them??

2還有一個(gè)黃金搭檔,開啟預(yù)編譯緩存參數(shù) cachePrepStmts= true,該參數(shù)同時(shí)控制client-side和server-side的緩存,默認(rèn)不開啟,Should the driver cache the parsing stage of PreparedStatements of client-side prepared statements, the "check" for suitability of server-side prepared and server-side prepared statements themselves?

為何說這兩個(gè)參數(shù)數(shù)黃金搭檔,因?yàn)閮烧咄瑫r(shí)使用效果才是最佳的。文章底部的兩篇參考博文都有對(duì)這塊性能的實(shí)驗(yàn),并且結(jié)論一致。通過客戶端預(yù)編譯、客戶端預(yù)編譯+緩存、服務(wù)端預(yù)編譯、服務(wù)端預(yù)編譯+緩存四組對(duì)照,結(jié)論 是用服務(wù)端預(yù)編譯+緩存 性能稍微比客戶端預(yù)編譯+緩存強(qiáng)。而如果服務(wù)端只開啟預(yù)編譯而不開啟緩存則性能最差。

????????參考博文2 結(jié)尾提到這么一句:但是對(duì)于不頻繁使用的語句,服務(wù)端預(yù)編譯本身會(huì)增加額外的round-trip,因此在實(shí)際開發(fā)中可以視情況定奪使用本地預(yù)編譯還是服務(wù)端預(yù)編譯以及哪些sql語句不需要開啟預(yù)編譯等。

在mybatis中insert,update,select,delete 標(biāo)簽中有一項(xiàng)statementType設(shè)置。(http://www.itdecent.cn/p/2be7903e8158

?statementType可選項(xiàng) STATEMENT,PREPARED 或 CALLABLE 的一個(gè),讓 MyBatis 分別使用 Statement(非預(yù)編譯),PreparedStatement (預(yù)編譯)或 CallableStatement(執(zhí)行存儲(chǔ)過程)。默認(rèn)值:PREPARED。以前沒有太注意statementType這個(gè)設(shè)置,#和$的使用是需要配合statementType來使用的。所以下面寫了三個(gè)查詢測(cè)試一下

@Select({"select * from ${param1} where id=#{param2}"})

@Options(statementType =StatementType.STATEMENT)

XyxUser select2(String tablename,String uid);

結(jié)果execute error. select * from user where id=? ;占位符的位置不能被替換成參數(shù)值。

@Options(statementType =StatementType.PREPARED)

@Select({"select * from ${param1} where id=#{param2}"})

XyxUser select3(String tablename,String uid);

結(jié)果:查詢成功

@Select({"select * from ${param1} where id=${param2}"})

@Options(statementType =StatementType.STATEMENT)

XyxUser select4(String tablename,String uid);

結(jié)果:select * from user where id=abc91170;Unknown column 'abc91170' in 'where clause'

????通過上述三個(gè)查詢,驗(yàn)證$和#混用,與statementType搭配的情況得出以下結(jié)論:

????1 # 必須搭配preparedStatement使用,占位符才能獲取參數(shù)值。

????2 $可以在statement和preparedStatement中使用。

????3??${ } 僅僅為一個(gè)純碎的 string 替換,在動(dòng)態(tài) SQL 解析階段將會(huì)進(jìn)行變量替換,用來傳動(dòng)態(tài)表名、列名,作為sql結(jié)構(gòu)的拼接部分,如動(dòng)態(tài)tablename select * from ${tablename} ,

select * from user order by ${age}

????4?#{ } 被解析為一個(gè)參數(shù)占位符 ? ,直觀上就是值被加了“value”,用來傳遞參數(shù)值?select * from user where id=#{id}?。


參考博文:

1?https://cs-css.iteye.com/blog/1847772?

2?https://www.cnblogs.com/micrari/p/7112781.html??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容