mybatis提供了兩種支援動態sql的語法:#{} 和 ${}。
select * from t_user where username = '$';
select * from t_user where username = #;
username傳參一致的話,這兩種執行的結果是一樣的,但是這兩種方式在動態sql解析階段的處理是不一樣的。
{}解析為乙個jdbc預編譯語句(prepared statement)的引數標記符,把引數部分用佔位符 ? 代替。動態解析為:
select * from t_user where username = ?;
而傳入的引數將會經過preparedstatement方法的強制型別檢查和安全檢查等處理,最後作為乙個合法的字串傳入。
這種方式只會做簡單的字串替換,在動態sql解析階段將會進行變數替換,假如傳遞的引數為二師兄,最終處理結果如下:
select * from t_user where username = '二師兄' ;
這樣在預編譯之前的sql語句已經不包含變數了,因此可以看出 ${} 變數的替換階段是在動態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#
if (!stringutil.isempty(this.username))
或者也可以使用資料庫函式進行連線處理:
select * from t_user u where username like concat('%', #username#, '%')
注意:以上就可以發現在某些特定場景下只能用${},比如order by後的排序字段,表名、列名,因為需要替換為不變的常量。如果表名中使用#{}的話,會變成如下:select from #-->tablename傳參為t_user --->處理後變成 select from 't_user',沒有這樣的表名,這樣的話就會報錯了,order by 同理。
因為預編譯語句物件可以重複利用,把乙個sql預編譯後產生的preparedstatement物件快取下來,下次對於同乙個sql,可以直接使用快取的preparedstatement物件,mybatis預設情況下,對所有的sql進行預編譯,這樣的話 #{}的處理方式效能會相對高些。
總結:
能使用#{}的時候盡量使用#{}表名。
order by的排序字段作為變數時,使用${}。
你真的了解mybatis中 和 的區別嗎
1 會在處理時,將引數變為佔位符 來代替引數。而傳入的引數將會經過preparedstatement方法的強制型別檢查和安全檢查等處理,最後作為乙個合法的字串傳入。2 會將傳過來的引數先進行預編譯,預編譯後再執行 3 並且會為傳過來的引數自動加上單引號 4 最重要的是由於進行了預編譯,會有效的防止s...
你真的了解iaas PaaS SaaS的區別嗎?
1 什麼是iaas paas和saas?iaas 基礎設施即服務 基礎設施即服務 iaas 提供了雲計算基礎架構,包括伺服器 儲存 網路和作業系統。客戶無需購買伺服器 軟體 資料庫空間或網路裝置,只要按需購買這些資源的外包服務。一些大的iaas公司包括amazon,microsoft,vmware,...
你真的了解Java嗎?
三目運算子規則 如果第二個和第三個運算元具有相同的型別,那麼它就是條件表示式的類 型。換句話說,你可以通過繞過混合型別的計算來避免 煩。如果乙個運算元的型別是 t,t 表示 byte short 或 char,而另乙個運算元是乙個 int 型別的常量表示式,它的值是可以用型別 t 表示的,那麼條件表...