mybatis中的字符串拼接問題
mybatis字符串拼接
MyBatis中拼接字符串有兩種方式。
使用CONCAT 函數(shù)
SELECT * FROM user WHERE name LIKE CONCAT(CONCAT(‘%', #{name}), ‘%')
使用${ } 代替 #{ }
因?yàn)?{ }直接傳入SQL,而#{ }傳入的是字符串帶有引號(hào)
SELECT * FROM user WHERE name LIKE ‘%${name}%'
原因:
#{}能夠有效防止SQL注入,但是也有它的缺點(diǎn),它會(huì)把傳入的數(shù)據(jù)自動(dòng)加上一個(gè)雙引號(hào),所以如果要的是數(shù)字的話,就會(huì)比較尷尬。
而${}可以直接解析出原本的數(shù)據(jù),所以需要數(shù)值比較的話,還是要加${}。
mybatis 拼接動(dòng)態(tài)表名、字段名
在項(xiàng)目中遇到個(gè)需求是要?jiǎng)討B(tài)的根據(jù)前臺(tái)傳入的字段名稱和升降序條件在mybatis里動(dòng)態(tài)拼接sql語句進(jìn)行查詢?,F(xiàn)在對(duì)解決方法進(jìn)行下總結(jié),希望對(duì)遇到同樣問題的伙伴有些幫助。
動(dòng)態(tài)SQL是mybatis的強(qiáng)大特性之一,mybatis在對(duì)sql語句進(jìn)行預(yù)編譯之前,會(huì)對(duì)sql進(jìn)行動(dòng)態(tài)解析,解析為一個(gè)BoundSql對(duì)象,也是在此處對(duì)動(dòng)態(tài)sql進(jìn)行處理。
這里我們?cè)敿?xì)說下動(dòng)態(tài)表名和字段名。下面讓我們先來熟悉下mybatis里#{}與${}的用法:
在動(dòng)態(tài)sql解析過程,#{}與${}的效果是不一樣的:
#{ } 解析為一個(gè) JDBC 預(yù)編譯語句(prepared statement)的參數(shù)標(biāo)記符。
如以下sql語句
select * from user where name = #{name};
會(huì)被解析為:
select * from user where name = ?;
可以看到#{}被解析為一個(gè)參數(shù)占位符?。
${ } 僅僅為一個(gè)純碎的 string 替換,在動(dòng)態(tài) SQL 解析階段將會(huì)進(jìn)行變量替換
如以下sql語句:
select * from user where name = ${name};
當(dāng)我們傳遞參數(shù)“sprite”時(shí),sql會(huì)解析為:
select * from user where name = "sprite";
可以看到預(yù)編譯之前的sql語句已經(jīng)不包含變量name了。
綜上所得, ${ } 的變量的替換階段是在動(dòng)態(tài) SQL 解析階段,而 #{ }的變量的替換是在 DBMS 中。
#{}與${}的區(qū)別可以簡單總結(jié)如下:
- #{}將傳入的參數(shù)當(dāng)成一個(gè)字符串,會(huì)給傳入的參數(shù)加一個(gè)雙引號(hào)
- ${}將傳入的參數(shù)直接顯示生成在sql中,不會(huì)添加引號(hào)
- #{}能夠很大程度上防止sql注入,${}無法防止sql注入
${}在預(yù)編譯之前已經(jīng)被變量替換了,這會(huì)存在sql注入的風(fēng)險(xiǎn)。如下sql
select * from ${tableName} where name = ${name}
如果傳入的參數(shù)tableName為user; delete user; --,那么sql動(dòng)態(tài)解析之后,預(yù)編譯之前的sql將變?yōu)椋?/p>
select * from user; delete user; -- where name = ?; --之后的語句將作為注釋不起作用,頓時(shí)我和我的小伙伴驚呆了?。。】吹?jīng)],本來的查詢語句,竟然偷偷的包含了一個(gè)刪除表數(shù)據(jù)的sql,是刪除,刪除,刪除!??!重要的事情說三遍,可想而知,這個(gè)風(fēng)險(xiǎn)是有多大。
- ${}一般用于傳輸數(shù)據(jù)庫的表名、字段名等
- 能用#{}的地方盡量別用${}
進(jìn)入正題,通過上面的分析,相信大家可能已經(jīng)對(duì)如何動(dòng)態(tài)調(diào)用表名和字段名有些思路了。示例如下:
? <select id="getUser" resultType="java.util.Map" parameterType="java.lang.String" statementType="STATEMENT"> ? ? select? ? ? ? ? ${columns} ? ? from ${tableName} ? ? ? ? where COMPANY_REMARK = ${company} ? </select>
要實(shí)現(xiàn)動(dòng)態(tài)調(diào)用表名和字段名,就不能使用預(yù)編譯了,需添加statementType="STATEMENT"" 。
statementType:STATEMENT(非預(yù)編譯),PREPARED(預(yù)編譯)或CALLABLE中的任意一個(gè),這就告訴 MyBatis 分別使用Statement,PreparedStatement或者CallableStatement。默認(rèn):PREPARED。這里顯然不能使用預(yù)編譯,要改成非預(yù)編譯。
其次,sql里的變量取值是${xxx},不是#{xxx}。
因?yàn)?{}是將傳入的參數(shù)直接顯示生成sql,如${xxx}傳入的參數(shù)為字符串?dāng)?shù)據(jù),需在參數(shù)傳入前加上引號(hào),如:
String name = "sprite"; name = "'" + name + "'";
這樣,sql就變成:
select * from user where name = 'sprite';
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用SpringBoot+AOP實(shí)現(xiàn)可插拔式日志的示例代碼
這篇文章主要介紹了使用SpringBoot+AOP實(shí)現(xiàn)可插拔式日志的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07spring-boot報(bào)錯(cuò)java: 程序包javax.servlet.http不存在
當(dāng)springboot項(xiàng)目從2.7.x的升級(jí)到3.0.x的時(shí)候,會(huì)遇到一個(gè)問題java: 程序包javax.servlet.http不存在,下面就來具體介紹一下,感興趣的可以了解一下2024-08-08Java使用Runnable和Callable實(shí)現(xiàn)多線程的區(qū)別詳解
這篇文章主要為大家詳細(xì)介紹了Java使用Runnable和Callable實(shí)現(xiàn)多線程的區(qū)別之處,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2022-07-07SpringBoot實(shí)現(xiàn)WEB的常用功能案例詳解
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)WEB的常用功能,本文將對(duì)Spring Boot實(shí)現(xiàn)Web開發(fā)中涉及的三大組件Servlet、Filter、Listener以及文件上傳下載功能以及打包部署進(jìn)行實(shí)現(xiàn),需要的朋友可以參考下2022-04-04深入學(xué)習(xí)Java 動(dòng)態(tài)代理
Java 動(dòng)態(tài)代理機(jī)制的出現(xiàn),使得 Java 開發(fā)人員不用手工編寫代理類,只要簡單地指定一組接口及委托類對(duì)象,便能動(dòng)態(tài)地獲得代理類。下面小編和大家來一起學(xué)習(xí)一下吧2019-05-05SpringBoot中ApplicationEvent的使用步驟詳解
ApplicationEvent類似于MQ,是Spring提供的一種發(fā)布訂閱模式的事件處理方式,本文給大家介紹SpringBoot中ApplicationEvent的使用步驟詳解,感興趣的朋友跟隨小編一起看看吧2024-04-04Spring Boot中使用Server-Sent Events (SSE) 實(shí)
Server-Sent Events (SSE) 是HTML5引入的一種輕量級(jí)的服務(wù)器向?yàn)g覽器客戶端單向推送實(shí)時(shí)數(shù)據(jù)的技術(shù),本文主要介紹了Spring Boot中使用Server-Sent Events (SSE) 實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送教程,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03