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