1. 程式人生 > >MyBatis動態sql之${}和#{}區別

MyBatis動態sql之${}和#{}區別

where 語句 替換字符串 客戶端 字符 註釋 tab reason mybatis

前言

? 接觸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中。

註意安全哦

  1. 能使用#{}的地方就別用${}.

    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!!!**

  1. 表名作為變量時,必須使用${}.表名是字符串,使用 sql 占位符替換字符串時會帶上單引號 ‘‘,這會導致 sql 語法錯誤.

再簡單講講sql預編譯

定義:

? sql 預編譯指的是數據庫驅動在發送 sql 語句和參數給 DBMS 之前對 sql 語句進行編譯,這樣 DBMS 執行 sql 時,就不需要重新編譯。

為什麽需要預編譯

JDBC 中使用對象 PreparedStatement 來抽象預編譯語句,使用預編譯

    1. 預編譯階段可以優化 sql 的執行。
      預編譯之後的 sql 多數情況下可以直接執行,DBMS 不需要再次編譯,越復雜的sql,編譯的復雜度將越大,預編譯階段可以合並多次操作為一個操作。
    2. 預編譯語句對象可以重復利用。
      把一個 sql 預編譯後產生的 PreparedStatement 對象緩存下來,下次對於同一個sql,可以直接使用這個緩存的 PreparedState 對象。

MyBatis動態sql之${}和#{}區別