前言
在開發中使用Mybatis經常使用到#{}與${},依舊有很多開發者對二者的使用不是很清晰,正所謂好記性不如爛筆頭,特此總結一下。
在mybatis中動態 sql 是其主要特性之一,在 mapper 中定義的參數傳到 xml 中之后,在執行操作之前 mybatis 會對其進行動態解析。mybatis 提供了兩種支持動態 sql 的語法:#{} 以及 $ {},其最大的區別則是#{}方式能夠很大程度防止sql注入(安全),${}方式無法防止Sql注入。什么??不懂什么是Sql注入?額。。。Sql注入指的是程序解析時會將你傳入的參數作為原來SQL語句的一部分,打亂原來SQL的結構,而通常我們只是需要傳入一個參數而已.
徹底理解SQL注入
什么?還不懂SQL注入,我湖了QAQ。。。那就來個最簡單的例子:一般開發,肯定是在前台有兩個輸入框,一個用戶名,一個密碼,會在后台里,讀取前台傳入的這兩個參數,拼成一段SQL,例如: select count(1) from tab where usesr=userinput and pass = passinput,把這段SQL連接數據后,看這個用戶名/密碼是否存在,如果存在的話,就可以登陸成功了,如果不存在,就報一個登陸失敗的錯誤。對吧。
但是有這樣的情況,這段SQL是根據用戶輸入拼出來,如果用戶故意輸入可以讓后台解析失敗的字符串,這就是SQL注入,例如,用戶在輸入密碼的時候,輸入 '''' ' or 1=1'', 這樣,后台的程序在解析的時候,拼成的SQL語句,可能是這樣的: select count(1) from tab where user=userinput and pass='' or 1=1; 看這條語句,可以知道,在解析之后,用戶沒有輸入密碼,加了一個恆等的條件 1=1,這樣,這段SQL執行的時候,返回的 count值肯定大於1的,如果程序的邏輯沒加過多的判斷,這樣就能夠使用用戶名 userinput登陸,而不需要密碼。
防止SQL注入,首先要對密碼輸入中的單引號進行過濾,再在后面加其它的邏輯判斷,或者不用這樣的動態SQL拼
關於 # { }
1、#{}表示一個占位符號 相當於
jdbc中的 ? 符號{}實現的是向prepareStatement中的預處理語句中設置參數值,sql語句中#{}表示一個占位符即?
2、#{}將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:
select * from user where id= #{user_id},如果傳入的值是11,那么解析成sql時的值為where id="11",
3、如果sql語句中只有
一個參數,此時參數名稱可以隨意定義
如果sql語句有多個參數,此時參數名稱應該是與當前表關聯[實體類的屬性名]或則[Map集合關鍵字],不能隨便寫,必須對應!如下圖

關於$ { }
1、$ {}將傳入的數據直接顯示生成在sql中。如:
select * from user where id= $ {user_id},如果傳入的值是11,那么解析成sql時的值為where id=11
2、
$ {value}中value值有限制只能寫對應的value值不能隨便寫,因為${}不會自動進行jdbc類型轉換
3、簡單來說,在
JDBC不支持使用占位符的地方,都可以使用${}
Mybatis中#{}與${}的區別
簡單來說區別就是
#{}方式能夠很大程度防止sql注入(安全),${}方式無法防止Sql注入
在
JDBC能使用占位符的地方,最好優先使用#{}
在
JDBC不支持使用占位符的地方,就只能使用${},典型情況就是 動態參數
比如 有兩張表,分別是emp_2017 和 emp_2018 .如果需要在查詢語句中 動態指定表名,就只能使用${}
<select>
select * from emp_ ${year}
<select>
再比如MyBatis 排序時使用order by 動態參數時,此時也只能使用${}
<select>
select * from dept order by ${name}
</select>
代碼案例
一般# {}與$ {}用的比較多的地方是模糊查詢方面,所以下面來一個模糊查詢的案例
使用#{}案例
1、映射文件
在User.xml配置文件中添加如下內容:
<!-- 如果返回多個結果,mybatis會自動把返回的結果放在list容器中 -->
<!-- resultType的配置和返回一個結果的配置一樣 -->
<select id="queryUserByUsername1" parameterType="string"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM `user` WHERE username LIKE #{username}
</select>
2、測試程序
MybatisTest中添加測試方法如下:
@Test
public void testQueryUserByUsername1() throws Exception {
// 4. 創建SqlSession對象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 執行SqlSession對象執行查詢,獲取結果User
// 查詢多條數據使用selectList方法
List<Object> list = sqlSession.selectList("queryUserByUsername1", "%王%");
// 6. 打印結果
for (Object user : list) {
System.out.println(user);
}
// 7. 釋放資源
sqlSession.close();
}
測試效果如下圖:

使用$ {}案例
1、映射文件:
在User.xml配置文件中添加如下內容:
<!-- 如果傳入的參數是簡單數據類型,${}里面必須寫value -->
<select id="queryUserByUsername2" parameterType="string"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM `user` WHERE username LIKE '%${value}%'
</select>
2.測試程序:
MybatisTest中添加測試方法如下:
@Test
public void testQueryUserByUsername2() throws Exception {
// 4. 創建SqlSession對象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 執行SqlSession對象執行查詢,獲取結果User
// 查詢多條數據使用selectList方法
List<Object> list = sqlSession.selectList("queryUserByUsername2", "王");
// 6. 打印結果
for (Object user : list) {
System.out.println(user);
}
// 7. 釋放資源
sqlSession.close();
}
當然兩個案例效果一致!
如果本文對你有一點點幫助,那么請點個贊唄,謝謝~
最后,若有不足或者不正之處,歡迎指正批評,感激不盡!如果有疑問歡迎留言,絕對第一時間回復!
歡迎各位關注我的公眾號,一起探討技術,向往技術,追求技術,說好了來了就是盆友喔...

