[05] 動態SQL


MyBatis的強大特性之一就是它的動態SQL,它能夠根據不一樣的條件動態地組成SQL語句進行執行。爲此,MyBatis提供了一系列強大的表達式,本章將就此進行學習,主要內容直接參考的是官方文檔《 動態 SQL》。

一、if

某些條件我須要時纔出現,不須要時就不出現,這種需求經常出如今根據用戶輸入的條件進行搜索的場景,下面來看官方給出的例子:
<select id="findActiveBlogWithTitleLike" resultType="Blog">
    SELECT * FROM BLOG
    WHERE state = 'ACTIVE'
    <if test="title != null">
        AND title LIKE #{title}
    </if>
</select>

若是傳入了title,那麼就會對「title」進行模糊查詢返回結果。你甚至能夠多條件考慮:
<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG WHERE state = 'ACTIVE'
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
</select>

二、choose / when / otherwise

choose / when / otherwise 三種元素結合起來使用,相似於Java中的switch語句,看了下面這個例子我想你必定能明白:
<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG WHERE state = 'ACTIVE'
    <choose>
        <when test="title != null">
            AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
            AND author_name like #{author.name}
        </when>
        <otherwise>
            AND featured = 1
        </otherwise>
    </choose>
</select>

三、where / set / trim

3.1 where

咱們先看下面這個例子:
<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG
    WHERE
    <if test="state != null">
        state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
</select>

看似沒有什麼毛病,但假如全部的 if 條件都沒有符合怎麼辦?SQL語句會變成這樣:SELECT * FROM BLOG  WHERE,這顯然是個錯誤的語句。假設只匹配了第二個 if,那麼語句又會變成這樣:SELECT * FROM BLOG  WHERE AND title like ‘someTitle’,這顯然也是個錯誤的語句。

爲了解決上面的問題,你可使用 where 元素,就像下面這樣:
<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG
    <where>
        <if test="state != null">
            state = #{state}
        </if>
        <if test="title != null">
            AND title like #{title}
        </if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        </if>
    </where>
</select>

有了 where 元素,你沒必要專門再寫WHERE關鍵字,它會在至少一個子元素條件知足的狀況下插入到SQL語句中,甚至你開頭寫的是 「AND」 或 「OR」,where 元素也會將它們去掉。

3.2 set

相似於 where 元素,用在 update 語句中的動態解決方案叫作 set,看以下例:
<update id="updateAuthorIfNecessary">
    update Author
    <set>
        <if test="username != null">username=#{username},</if>
        <if test="password != null">password=#{password},</if>
        <if test="email != null">email=#{email},</if>
        <if test="bio != null">bio=#{bio}</if>
    </set>
    where id=#{id}
</update>

如上例,set 元素會動態前置 SET 關鍵字,同時會刪掉無關的逗號(好比只有第二個 if 知足條件的時候)

3.3 trim

trim 元素則是一個可以靈活設置的元素,你甚至能夠經過 trim 實現和 where 或 set 元素相同的功能。trim 元素有四個屬性:
  • prefix
  • prefixOverride
  • suffix
  • suffixOverride

prefix 表示 「 在前置添加的內容」,prefixOverride 則表示 「 覆蓋掉前置內容並添加prefix的內容」,注意, 這些屬性的做用都是當trim標籤內有SQL語句內容時纔會觸發。suffix 同理,不過是針對後置的。

多說無益,來看例子:
<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG
    <trim prefix="WHERE" prefixOverrides="AND |OR">
        <if test="state != null">
            state = #{state}
        </if>
        <if test="title != null">
            AND title like #{title}
        </if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        </if>
    </trim>
</select>

上例中trim的使用結果就是,它等同於 where 元素的效果,即:當有SQL語句出現(如上例有 if 知足),前置內容會添加 「WHERE」,若是遇到前置內容是 「AND 」 或者 「OR」 開頭,則先覆蓋掉前置內容(也即刪掉),再添加 prefix 的內容 「WHERE」。

同理,咱們也能夠利用 trim 的 prefix 和 suffixOverride 來實現 set 元素的效果:
<update id="updateAuthorIfNecessary">
    update Author
    <trim prefix="SET" suffixOverrides=",">
        <if test="username != null">username=#{username},</if>
        <if test="password != null">password=#{password},</if>
        <if test="email != null">email=#{email},</if>
        <if test="bio != null">bio=#{bio}</if>
    </trim>
    where id=#{id}
</update>

四、foreach

動態SQL還能夠對集合進行遍歷,這在構建IN條件語句,或者是批量插入內容時極爲常見:
<select id="selectPostIn" resultType="domain.blog.Post">
    SELECT *
    FROM POST P
    WHERE ID in
    <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

其中:
  • item - 當前迭代的元素
  • index - 當前迭代的次數(若是集合是Map,則index爲鍵)
  • open - 開頭字符串
  • separator - 元素間的分隔符
  • close - 結尾字符串

如上最終會造成諸如 「... WHERE ID in ( 10, 12, 23, 35, 99 )」 形式的SQL語句。 
相關文章
相關標籤/搜索