MyBatis動態sql之${}和#{}區別
前言
? 接觸mybatis也是在今年步入社會之後,想想也半年多了,缺沒時間去系統的學習,只知道大概,也是慚愧。
? 不知道有多少剛畢業的同學和我一樣,到現在還沒仔仔細細去了解你每天都會見到使用到的框架呢?
? 什麽?你也不知道mybatis動態sql中${}和#{}的差異?其實我也是今天才知道的,我們一起來學習一下吧。
正文
不夠刺激,再增加一點前戲
? 在mybatis中,使用sql查詢時,經常需要動態傳遞參數。大家往往會采用以下方式:
-- 以根據order_no 查詢訂單信息為例
-- ①
select * from order where order_no = #{orderNo}
-- ②
select * from order where order_no = ‘${orderNo}‘
咦,不對!!!如果orderNo=’2017111695468435844135’,要最後執行後的結果與下面的語句執行結果一樣,到底是用①還是②呢?
select * from order where order_no = ‘2017111695468435844135‘
好吧。。。其實兩種方式得到的結果是相同的。
but 在某些情況下,我們只能使用二者其一!!!
主題開始了
動態sql 是mybatis優於其他ORM框架的一個重要原因之一。
mybatis 在對 sql 語句進行預編譯之前,會對 sql 進行動態解析,解析為一個BoundSql 對象,也是在此處對動態 SQL 進行處理的,使得#{}和${}在此處產生了差異。
#{}解析為一個JDBC中prepared statement的參數標記符
即:
select * from order where order_no = #{orderNo}
被解析為:
select * from order where order_no = ?
也即是,#{}被解析為一個參數占位符?.
${}則僅僅是一個純粹的字符串替換
即:
select * from order where order_no = ‘${orderNo}‘
被解析為:
select * from order where order_no = ‘2017111695468435844135‘
也就是說,使用${}在預編譯之前已經不包含變量name了,而#{}的變量替換是在DBMS中。
註意安全哦
-
能使用#{}的地方就別用${}.
reason:1.使用#{},相同的預編譯sql可以重復利用,性能比${}高;
? 2. ${}在預編譯之前已經被變量替換了,會存在sql註入問題。
? 例如:
select * from ${tableName} where order_no = #{orderNo}
如果從客戶端傳入的tableName = “order;delete order; – “,那麽sql動態解析之後,預編譯之前的sql將變為:
select * from order;delete order; -- where order_no = #{orderNo}
– 之後的語句被註釋了,然後,sql完全大變了。。。interesting!!!**
- 表名作為變量時,必須使用${}.表名是字符串,使用 sql 占位符替換字符串時會帶上單引號
‘‘
,這會導致 sql 語法錯誤.
再簡單講講sql預編譯
定義:
? sql 預編譯指的是數據庫驅動在發送 sql 語句和參數給 DBMS 之前對 sql 語句進行編譯,這樣 DBMS 執行 sql 時,就不需要重新編譯。
為什麽需要預編譯
JDBC 中使用對象 PreparedStatement 來抽象預編譯語句,使用預編譯
- 預編譯階段可以優化 sql 的執行。
預編譯之後的 sql 多數情況下可以直接執行,DBMS 不需要再次編譯,越復雜的sql,編譯的復雜度將越大,預編譯階段可以合並多次操作為一個操作。 - 預編譯語句對象可以重復利用。
把一個 sql 預編譯後產生的 PreparedStatement 對象緩存下來,下次對於同一個sql,可以直接使用這個緩存的 PreparedState 對象。
MyBatis動態sql之${}和#{}區別