Mybatis中#{}與${}的區(qū)別詳解
前言
在開(kāi)發(fā)中使用Mybatis經(jīng)常使用到#{}與${},依舊有很多開(kāi)發(fā)者對(duì)二者的使用不是很清晰,正所謂好記性不如爛筆頭,特此總結(jié)一下。
在mybatis中動(dòng)態(tài) sql 是其主要特性之一,在 mapper 中定義的參數(shù)傳到 xml 中之后,在執(zhí)行操作之前 mybatis 會(huì)對(duì)其進(jìn)行動(dòng)態(tài)解析。mybatis 提供了兩種支持動(dòng)態(tài) sql 的語(yǔ)法:#{} 以及 $ { }, 其最大的區(qū)別則是前者方式能夠很大程度防止sql注入(安全),后者方式無(wú)法防止Sql注入 。什么??不懂什么是Sql注入?額。。。Sql注入指的是程序解析時(shí)會(huì)將你傳入的參數(shù)作為原來(lái)SQL語(yǔ)句的一部分,打亂原來(lái)SQL的結(jié)構(gòu),而通常我們只是需要傳入一個(gè)參數(shù)而已.
徹底理解SQL注入
什么?還不懂SQL注入,我湖了QAQ。。。那就來(lái)個(gè)最簡(jiǎn)單的例子:一般開(kāi)發(fā),肯定是在前臺(tái)有兩個(gè)輸入框,一個(gè)用戶名,一個(gè)密碼,會(huì)在后臺(tái)里,讀取前臺(tái)傳入的這兩個(gè)參數(shù),拼成一段SQL,例如: select count(1) from tab where usesr=userinput and pass = passinput,把這段SQL連接數(shù)據(jù)后,看這個(gè)用戶名/密碼是否存在,如果存在的話,就可以登陸成功了,如果不存在,就報(bào)一個(gè)登陸失敗的錯(cuò)誤。對(duì)吧。 但是有這樣的情況,這段SQL是根據(jù)用戶輸入拼出來(lái),如果用戶故意輸入可以讓后臺(tái)解析失敗的字符串,這就是SQL注入,例如,用戶在輸入密碼的時(shí)候,輸入 '''' ' or 1=1'', 這樣,后臺(tái)的程序在解析的時(shí)候,拼成的SQL語(yǔ)句,可能是這樣的: select count(1) from tab where user=userinput and pass='' or 1=1; 看這條語(yǔ)句,可以知道,在解析之后,用戶沒(méi)有輸入密碼,加了一個(gè)恒等的條件 1=1,這樣,這段SQL執(zhí)行的時(shí)候,返回的 count值肯定大于1的,如果程序的邏輯沒(méi)加過(guò)多的判斷,這樣就能夠使用用戶名 userinput登陸,而不需要密碼。 防止SQL注入,首先要對(duì)密碼輸入中的單引號(hào)進(jìn)行過(guò)濾,再在后面加其它的邏輯判斷,或者不用這樣的動(dòng)態(tài)SQL拼
關(guān)于 # { }
1、#{}表示一個(gè)占位符號(hào) 相當(dāng)于 jdbc 中的 ? 符號(hào) #{}實(shí)現(xiàn)的是向prepareStatement中的預(yù)處理語(yǔ)句中設(shè)置參數(shù)值,sql語(yǔ)句中#{}表示一個(gè)占位符即?
2、#{}將傳入的數(shù)據(jù)都當(dāng)成一個(gè)字符串,會(huì)對(duì)自動(dòng)傳入的數(shù)據(jù)加一個(gè)雙引號(hào)。如: select * from user where id= #{user_id} ,如果傳入的值是11,那么解析成sql時(shí)的值為 where id="11" ,
3、如果sql語(yǔ)句中只有 一個(gè)參數(shù) ,此時(shí)參數(shù)名稱可以 隨意定義 如果sql語(yǔ)句有 多 個(gè)參數(shù),此時(shí)參數(shù)名稱應(yīng)該是與當(dāng)前表關(guān)聯(lián)[實(shí)體類的屬性名]或則[Map集合關(guān)鍵字], 不能隨便寫,必須對(duì)應(yīng) !如下圖
關(guān)于$ { }
1、 {user_id} ,如果傳入的值是11,那么解析成sql時(shí)的值為 where id=11`
2、 $ {value} 中 value 值有限制只能寫對(duì)應(yīng)的value值不能隨便寫,因?yàn)?${} 不會(huì)自動(dòng)進(jìn)行jdbc類型轉(zhuǎn)換
3、簡(jiǎn)單來(lái)說(shuō),在 JDBC 不支持使用占位符的地方,都可以使用 ${}
Mybatis中#{}與${}的區(qū)別
簡(jiǎn)單來(lái)說(shuō)區(qū)別就是
#{}方式能夠很大程度防止sql注入(安全),${}方式無(wú)法防止Sql注入
在 JDBC 能使用占位符的地方,最好優(yōu)先使用 #{}
在 JDBC 不支持使用占位符的地方,就只能使用 ${} ,典型情況就是 動(dòng)態(tài)參數(shù)
比如 有兩張表,分別是 emp_2017 和 emp_2018 .如果需要在查詢語(yǔ)句中 動(dòng)態(tài)指定表名 ,就只能使用${}
<select>
select * from emp_ ${year}
<select>
再比如MyBatis 排序時(shí)使用 order by 動(dòng)態(tài)參數(shù) 時(shí),此時(shí)也只能使用${}
<select>
select * from dept order by ${name}
</select>
代碼案例
一般# {}與$ {}用的比較多的地方是模糊查詢方面,所以下面來(lái)一個(gè)模糊查詢的案例
使用#{}案例
1、映射文件
在User.xml配置文件中添加如下內(nèi)容:
<!-- 如果返回多個(gè)結(jié)果,mybatis會(huì)自動(dòng)把返回的結(jié)果放在list容器中 -->
<!-- resultType的配置和返回一個(gè)結(jié)果的配置一樣 -->
<select id="queryUserByUsername1" parameterType="string"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM `user` WHERE username LIKE #{username}
</select>
2、測(cè)試程序
MybatisTest中添加測(cè)試方法如下:
@Test
public void testQueryUserByUsername1() throws Exception {
// 4. 創(chuàng)建SqlSession對(duì)象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 執(zhí)行SqlSession對(duì)象執(zhí)行查詢,獲取結(jié)果User
// 查詢多條數(shù)據(jù)使用selectList方法
List<Object> list = sqlSession.selectList("queryUserByUsername1", "%王%");
// 6. 打印結(jié)果
for (Object user : list) {
System.out.println(user);
}
// 7. 釋放資源
sqlSession.close();
}
測(cè)試效果如下圖:
使用$ {}案例
1、映射文件:
在User.xml配置文件中添加如下內(nèi)容:
<!-- 如果傳入的參數(shù)是簡(jiǎn)單數(shù)據(jù)類型,${}里面必須寫value -->
<select id="queryUserByUsername2" parameterType="string"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM `user` WHERE username LIKE '%${value}%'
</select>
2.測(cè)試程序:MybatisTest中添加測(cè)試方法如下:
@Test
public void testQueryUserByUsername2() throws Exception {
// 4. 創(chuàng)建SqlSession對(duì)象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 執(zhí)行SqlSession對(duì)象執(zhí)行查詢,獲取結(jié)果User
// 查詢多條數(shù)據(jù)使用selectList方法
List<Object> list = sqlSession.selectList("queryUserByUsername2", "王");
// 6. 打印結(jié)果
for (Object user : list) {
System.out.println(user);
}
// 7. 釋放資源
sqlSession.close();
}
當(dāng)然兩個(gè)案例效果一致!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- MyBatis中#{}?和?${}?的區(qū)別和動(dòng)態(tài)?SQL詳解
- mybatis中${}和#{}的區(qū)別以及底層原理分析
- MyBatis #{}和${} |與數(shù)據(jù)庫(kù)連接池使用詳解
- MyBatis中使用#{}和${}占位符傳遞參數(shù)的各種報(bào)錯(cuò)信息處理方案
- Mybatis關(guān)于動(dòng)態(tài)排序 #{} ${}問(wèn)題
- mybatis中#{}和${}的區(qū)別詳解
- MyBatis中#{}和${}有哪些區(qū)別
- mybatis中${}和#{}取值的區(qū)別分析
- MyBatis中#{}占位符與${}拼接符的用法說(shuō)明
- 詳解Mybatis中的 ${} 和 #{}區(qū)別與用法
- Mybatis之#{}與${}的區(qū)別使用詳解
- MyBatis中 #{} 和 ${} 的區(qū)別小結(jié)
相關(guān)文章
通過(guò)實(shí)例解析Java分布式鎖三種實(shí)現(xiàn)方法
這篇文章主要介紹了通過(guò)實(shí)例解析Java分布式鎖三種實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
Java基于API接口爬取商品數(shù)據(jù)的示例代碼
Java作為一種流行的編程語(yǔ)言,可以用于編寫程序來(lái)調(diào)用這些API接口,從而獲取商品數(shù)據(jù),本文將介紹如何使用Java基于API接口爬取商品數(shù)據(jù),包括請(qǐng)求API、解析JSON數(shù)據(jù)、存儲(chǔ)數(shù)據(jù)等步驟,并提供相應(yīng)的代碼示例,感興趣的朋友跟隨小編一起看看吧2023-10-10
Maven項(xiàng)目打包成可執(zhí)行Jar文件步驟解析
這篇文章主要介紹了Maven項(xiàng)目如何打包成可執(zhí)行Jar文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
springboot配置mysql數(shù)據(jù)庫(kù)spring.datasource.url報(bào)錯(cuò)的解決
這篇文章主要介紹了springboot配置mysql數(shù)據(jù)庫(kù)spring.datasource.url報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
springboot使用國(guó)產(chǎn)加密算法方式,sm2和sm3加解密demo
這篇文章主要介紹了springboot使用國(guó)產(chǎn)加密算法方式,sm2和sm3加解密demo,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列詳解
這篇文章主要介紹了Java常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列詳解,棧(Stack) 是一種基本的數(shù)據(jù)結(jié)構(gòu),具有后進(jìn)先出(LIFO)的特性,類似于現(xiàn)實(shí)生活中的一疊盤子,棧用于存儲(chǔ)一組元素,但只允許在棧頂進(jìn)行插入(入棧)和刪除(出棧)操作,需要的朋友可以參考下2023-10-10
SpringBoot如何使用TestEntityManager進(jìn)行JPA集成測(cè)試
TestEntityManager是Spring Framework提供的一個(gè)測(cè)試框架,它可以幫助我們進(jìn)行 JPA 集成測(cè)試,在本文中,我們將介紹如何使用 TestEntityManager 進(jìn)行 JPA 集成測(cè)試,感興趣的跟著小編一起來(lái)學(xué)習(xí)吧2023-06-06

