mybatis中動態sql的實現與使用
首先引用一段mybatis文件中的話:
動態 SQL
MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。
雖然在以前使用動態 SQL 並非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 對映語句中的強大的動態 SQL 語言得以改進這種情形。
動態 SQL 元素和 JSTL 或基於類似 XML 的文字處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。MyBatis 採用功能強大的基於 OGNL 的表示式來淘汰其它大部分元素。
下面記錄各個元素的巧妙使用:
一、if
如果採用xml的方式配置mybatis,假設現在要做兩個查詢:
1.查詢一個物件的所有記錄。
2.查詢一個物件所有記錄中包含一個傳過來的字串的模糊查詢。
那麼不使用動態SQL應該這樣寫:(這樣顯得很麻煩)
<select id="productList" resultType="Product"> select p.id,p.name,p.price from product p </select> <select id="getProductsLikeName" parameterType="String" resultType="Product"> select p.id,p.name,p.price from product p where name like concat('%',#{nameaa},'%') </select>
對應介面:
List<Product> productList();
List<Product> getProductsLikeName(String name);
採用if:如果沒有傳入Product物件就查詢所有,傳入了物件就根據product.name的值進行模糊查詢,方便太多了。
<select id="list" resultType="Product" parameterType="Product"> select p.id,p.name,p.price from product p <if test="name!=null"> where name like concat('%',#{name},'%') </if> </select>
對應介面:
List<Product> list();
List<Product> list(Product product);
二、where
如果有多個if來判斷,前一個if不成立,可能就會出現多出一個and的錯誤情況。
where>標籤會進行自動判斷
如果任何條件都不成立,那麼就在sql語句裡就不會出現where關鍵字
如果有任何條件成立,會自動去掉多出來的 and 或者 or。
例如:除了根據name模糊查詢,再加一個價格的篩選。
(如果不用where只用兩個if,
假設name沒有傳值,那麼sql語句就會變成 select p.id,p.name,p.price from product p and price>#{price}
這顯然會報錯。
)
<select id="list" resultType="Product" parameterType="Product">
select p.id,p.name,p.price from product p
<where>
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="price!=null">
and price>#{price}
</if>
</where>
</select>
三、set
在update語句裡也會碰到多個欄位相關的問題。 在這種情況下,就可以使用set標籤:
name或者price有值的時候才進行sql拼接。
<update id="updateProduct" parameterType="Product" >
update product
<set>
<if test="name!=null">name=#{name},</if>
<if test="price!=null">price=#{price}</if>
</set>
where id=#{id}
</update>
四、trim
如果 where 元素沒有按正常套路出牌,我們可以通過自定義 trim 元素來定製 where 元素的功能。比如,和 where 元素等價的自定義 trim 元素為:
prefixOverrides 屬性會忽略通過管道分隔的文字序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 屬性中的內容,並且插入 prefix 屬性中指定的內容。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
例子:這裡把<where>改為了<trim prefix="WHERE" prefixOverrides="AND |OR ">。
<select id="list" resultType="Product" parameterType="Product">
select p.id,p.name,p.price from product p
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="price!=null">
and price>#{price}
</if>
</trim>
</select>
例子:<set>改為了<trim prefix="SET" suffixOverrides=",">。
特別注意:我看的文件中提示出如果最後一個if不成立,刪去的是字尾值,同時添加了字首值。那麼sql語句的結尾就會多出一個逗號。
<update id="updateProduct" parameterType="Product" >
update product
<trim prefix="SET" suffixOverrides=",">
<if test="name!=null">name=#{name},</if>
<if test="price!=null">price=#{price}</if>
</trim>
where id=#{id}
</update>
五、choose, when, otherwise
有時我們不想應用到所有的條件語句,而只想從中擇其一項。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
例子:如果傳入的Product物件沒有設定name和price的值,那麼就執行查詢id大於1的記錄,如果name或price有值,那麼就查詢對應的,並且不執行<otherwise>中的語句。 非常的像switch語句。
<select id="list1" resultType="Product">
SELECT p.id,p.name,p.price FROM product p
<where>
<choose>
<when test="name != null">
and name like concat('%',#{name},'%')
</when>
<when test="price !=null and price != 0">
and price > #{price}
</when>
<otherwise>
and id >1
</otherwise>
</choose>
</where>
</select>
六、foreach
foreach標籤通常用於in 這樣的語法裡。
例子:查詢id為1和4的記錄。
<select id="list3" resultType="Product">
SELECT p.id,p.name,p.price FROM product p
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
七、bind
bind 元素可以從 OGNL 表示式中建立一個變數並將其繫結到上下文。
<!-- 本來的模糊查詢方式 -->
<!-- <select id="list4" resultType="Product"> -->
<!-- select p.id,p.name,p.price from product p where name like concat('%',#{0},'%') -->
<!-- </select> -->
<select id="list4" resultType="Product">
<bind name="likename" value="'%' + name + '%'" />
select p.id,p.name,p.price from product p where name like #{likename}
</select>
引用書籍中的話:
bind取代模糊查詢的好處是提高了程式碼的可移植性。
在進行模糊查詢時,如果是MySQL資料庫,常常用到的是一個concat,它用'%'和引數相連。然而在Oracle資料庫則沒有,Oracle資料庫用連線符號”||“。 當我們有了bind元素,就不必使用資料庫語言,而是使用MyBatis的動態SQL即可完成。
所以無論是MySQL還是Oracle都可以使用這樣的語句,從而提高了程式碼的可移植性。