Mybatis 中 #{} 與 ${} 的區別

 兩個 符號都是取值的,但是他們的區別是什麼呢?


一:問題的由來?

最近在工作中有個點擊排序的功能調試了許久,終尋因,總結之。 
  需求是這樣的,頁面有個table,有一列的上下箭頭可點擊並排序。對於這種需求,我的mybatis.xml的sql配置寫成了如下:

<if test="map.ColumnNameSort!=null and map.ColumnNameSort!=''"> 
  ORDER BY columnName #{map.ColumnNameSort} 
</if>

  ColumnNameSort即前端傳的排序方式,asc或者desc。

  然後,預計它的輸出應該是類似於下面這樣的

ORDER BY columnName desc

  但是,真正跑起來時,排序的效果一直沒出現,經常一番查找,發現是mybatis 的’#{}’傳值的問題,它將sql語句編譯成了如下

ORDER BY columnName 'desc' 或者 ORDER BY columnName 'asc'

  這樣,desc或者asc就成了字符串而不是關鍵字,sql語句的意思是columnName的別名是desc或者asc,沒加排序關鍵字時默認是正序排序,成了如下

ORDER BY columnName "desc" asc 或者 ORDER BY columnName "asc" asc

  排序沒效果的問題找到原因了,解決之,mybatis提供了另一種綁定參數的方式–${param},將sql配置改爲

ORDER BY columnName ${map.ColumnNameSort}

  這樣一來,mybatis會直接將ColumnNameSort的值加入sql中,不會轉義。正確結果:

ORDER BY columnName desc

二:對比區別

對於mybatis中#和$綁定參數的區別做個總結,避免以後類似的問題發生。  

  1. #{}將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:order by #{id},如果傳入的值是111,那麼解析成sql時的值爲order by “111”, 如果傳入的值是id,則解析成的sql爲order by “id”。

  2. ${}將傳入的數據直接顯示生成在sql中。如:order by 
    ${id},如果傳入的值是111,那麼解析成sql時的值爲order by 111, 如果傳入的值是id,則解析成的sql爲order 
    by id。

  3. #方式能夠很大程度防止sql注入。

  4. $方式無法防止Sql注入。

  5. $方式一般用於傳入數據庫對象,例如傳入表名.

  6. 一般能用#的就別用$.

PS:

在mybatis接口mapper文件中引用傳入的參數是通過#{param}或者${param}來使用的。

至於mybatisl中#{}和${}的區別其實很簡單,但是之前一直沒有理解清楚,網上一堆錯誤的理解。所以在這裏記錄一下

其實這個問題很簡單。

select * from t_user where name = #{param}

使用#{}就等於使用了PrepareStatement這種佔位符的形式。可以防止sql注入等等問題。

select count(*), from t_user group by ${param}

這種group by 字段 ,order by 字段,表名,字段名等沒法使用佔位符的就需要使用${}



這裏展開說一下關於PrepareStatement的好處。

數據庫有個功能叫綁定變量,就是針對一條sql預編譯生成多個執行計劃,如果只是參數改變的重複sql,綁定變量則會提高很大的性能。PrepareStatement就會使用數據庫的綁定變量的功能。


TIP:#{} preparement State  預處理  佔位符 防止sql 注入


發佈了64 篇原創文章 · 獲贊 61 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章