動態SQL就是在SQL語句中新增一些標籤,以完成某些邏輯。通常用到的動態SQL標籤有<if>、<choose>、<where>、<trim>、<set>、<foreach>、<bind>、<sql>等。
1、if
if是簡單的條件判斷,通過if語句我們可以實現某些簡單的條件選擇,一個例子的程式碼如下:
<select id="dynamicIfTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 11 = 1
<if test="title != null">
and title = #{title}
</if>
<if test="content != null">
and content = #{content}
</if>
<if test="owner != null">
and owner = #{owner}
</if>
</select>
2、choose
choose標籤的作用就相當於JAVA中的switch語句,只不過不是使用case與default搭配,而是使用when和otherwise搭配。一個例子的程式碼如下:
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 11 = 1
<choose>
<when test="title != null">
and title = #{title}
</when>
<when test="content != null">
and content = #{content}
</when>
<otherwise>
and owner = "owner1"
</otherwise>
</choose>
</select>
choose語句和JAVA中的switch語句類似,都是按順序從上向下判斷,一旦有某個when的條件滿足的時候,就會跳出choose,當所有when中的條件都不滿足,就會執行otherwise中的語句。
3、trim
trim標籤的作用是可以在自己包含的內容前後加上字首或字尾,與之對應的屬性是prefix和suffix;trim標籤也可以把包含內容中首、尾部的某些內容覆蓋(即忽略),對應的屬性是prefixOverrides和suffixOverrides。一個例子的程式碼如下:
<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
select * from t_blog
<trim prefix="where" prefixOverrides="and|or">
<if test="title != null">
title = #{title}
</if>
<if test="content != null">
and content = #{content}
</if>
<if test="owner != null">
or owner = #{owner}
</if>
</trim>
</select>
上面這段程式碼的意思是:在這段程式碼的最前面加一個字首where,然後把可能位於最前面的and或or給覆蓋(忽略)掉。正因為trim標籤有這樣的功能,所以我們也可以非常簡單的利用trim來代替where元素的功能。
4、where
where標籤的作用是為了簡化SQL語句中where的條件判斷的,一個例子的程式碼如下:
<select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
select * from t_blog
<where>
<if test="title != null">
and title = #{title}
</if>
<if test="content != null">
and content = #{content}
</if>
<if test="owner != null">
and owner = #{owner}
</if>
</where>
</select>
where標籤的作用是會在寫<where>的地方自動輸出一個where,即省略了SQL語句中的where關鍵字;像上面這段動態SQL,假如第一個判斷成立,那麼MyBatis為我們生成的SQL語句是:select * from t_blog where title = #{title}; ,而不是:select * from t_blog where and title = #{title},即MyBatis的動態SQL會自動把第一個多餘的and去掉,如果將這裡的and換成or,也會有同樣的效果。
5、set
set標籤主要用在更新操作的時候,它的功能和where元素差不多,主要是在包含的語句最前面新增一個set字首,然後如果所包含的語句是以逗號結尾的話就將該逗號忽略,如果set包含的內容為空的話就會報錯。一個例子的程式碼如下:
<update id="dynamicSetTest" parameterType="Blog">
update t_blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="content != null">
content = #{content},
</if>
<if test="owner != null">
owner = #{owner}
</if>
</set>
where id = #{id}
</update>
在上面這段程式碼中,如果set中的三個判斷都不成立,即set中的內容為空,那麼就會報錯。有了set標籤,我們就可以動態的更新那些修改了的欄位了。
6、foreach
foreach標籤主要用於構建in條件,它可以在SQL語句中迭代一個集合。foreach標籤的屬性有item、index、collection、open、separator、close,其中,item表示集合中的元素進行迭代時的別名;index指定當前迭代的位置;open指定這段SQL的字首;separator指定每個迭代元素之間的分隔符;close指定這段SQL的字尾;collection指定集合型別:
(1)如果傳入List列表,則collection的屬性值為list,示例程式碼如下:
<select id="dynamicForeachTest" resultType="Blog">
select * from t_blog where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
(2)如果傳入陣列,則collection的屬性值為array,示例程式碼如下:
<select id="dynamicForeach2Test" resultType="Blog">
select * from t_blog where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
(3)如果傳入Map集合,則collection的屬性值是Map集合的key,示例程式碼如下(在這個例子中,Map中儲存著一個key是ids的List):
<select id="dynamicForeach3Test" resultType="Blog">
select * from t_blog where title like "%"#{title}"%" and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
(4)如果是Set集合,且Set中每個元素的型別是Map.Entry時,則collection的屬性值為collection,此時index屬性代表Map.Entry的key,item屬性代表Map.Entry的value。示例程式碼如下:
<select id="dynamicForeachTest" resultType="Blog">
select * from t_blog where id in
<!-- 遍歷的物件是Map.Entry時,index代表對應的key,item代表對應的value -->
<foreach collection="collection" index="key" item="value" open="(" separator="," close=")">
#{key}, #{value}
</foreach>
</select>
7、bind
bind標籤主要用於模糊查詢的字串拼接,一個例子的程式碼如下:
<select id="fuzzyQuery" resultType="Blog" parameterType="java.lang.String">
<bind name="titleLike" value="'%'+_parameter+'%'"/>
select * from t_blog where title like #{titleLike}
</select>
8、SQL
有時,如果動態SQL中包含的程式碼過長,且有可能在不同的SQL語句中重複用到,那麼就可以將這段SQL提取出來作為SQL片段(也相當於封裝)。抽取出來的SQL語句使用<sql>標籤包裹,在使用到某個SQL片段時,使用<include>標籤引入SQL片段。一個例子的程式碼如下:
<!-- 被抽取出來的SQL片段(id是這個SQL片段的唯一標識) -->
<!-- 注意:SQL片段一般都是基於單表建立的;SQL片段中最好不要包括where語句 -->
<sql id="blog_query">
<if test="title!=null">
and title = #{title}
</if>
</sql> <select id="findEmplyeeListDynamicSQL" parameterType="Blog" resultType="Blog">
SELECT * FROM t_blog
<where>
<!-- 引用抽取出來的SQL片段。如果要引用的SQL片段在其他mapper檔案中,則需要在前面新增namespace -->
<include refid="blog_query"></include>
</where>
</select>