天天看點

mybatis中${}、 #{}差別及應用場景

mybatis中${}、 #{}差別及應用場景

動态sql是mybatis的主要特性之一。在mapper中定義的參數傳到xml中之後,在查詢之前mybatis會對其進行動态解析。

mybatis提供了兩種支援動态sql的文法:#{} 、${}。

select * from t_user where username = '${username}';
select * from t_user where username = #{username};      

username傳參一緻的話,這兩種執行的結果是一樣的,但是這兩種方式在動态sql解析階段的處理是不一樣的。

#{}

#{ }是預編譯處理,MyBatis在處理#{ }時,它會将sql中的#{ }替換為?,然後調用PreparedStatement的set方法來指派,傳入字元串後,會在值兩邊加上單引号

${}

{ }時,它會将sql中的${ }替換為變量的值,傳入的資料不會加兩邊加上單引号。

這樣在預編譯之前的sql語句已經不包含變量了,是以可以看出${} 變量的替換階段是在動态SQL解析階段。

sql注入

1、注意:使用${ }會導緻sql注入,不利于系統的安全性!

如果傳入的username 為 a’ or '1=1,那麼使用${}處理後直接替換字元串的sql就解析為:

select * from t_user where username = a' or '1=1' ;      

這樣的話所有的使用者資料就被查出來了,這樣就屬于SQL注入。

如果使用#{},經過sql動态解析和預編譯,會把單引号轉義為’那麼sql最終解析為:

select * from t_user where username = "a\' or \'1=1 ";      

這樣會查不出任何資料,有效阻止sql注入

有的業務場景經常用到模糊查詢,也就是like處理,推薦使用以下處理方式:

t_user.username like #username#      

java代碼裡:

if (!StringUtil.isEmpty(this.username)) {
  table.setUsername("%" + this.username + "%");
}      

或者也可以使用資料庫函數進行連接配接處理:

select  * from t_user u where username  like CONCAT('%', #username#, '%')      

特定場景

注意:以上就可以發現在某些特定場景下隻能用${},比如order by 後的排序字段,表名、列名,因為需要替換為不變的常量。如果表名中使用#{}的話,會變成如下:

​select * from #{tablename}-->tablename​

​​傳參為​

​t_user​

​​—>處理後變成 ​

​select * from 't_user'​

​,沒有這樣的表名,這樣的話就會報錯了,order by 同理。

性能考慮

總結