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 同理。