平時在開發中,針對動態sql這塊目前是薄弱點,本身根據官網在對應項目邊測試邊寫博客,此篇只是爲了加深動態sql的熟練度,有不到之處敬請批評指正!sql
使用動態 SQL 最多見情景是根據條件包含 where 子句的一部分。好比:數組
<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> </select>
這條語句提供了可選的查找文本功能。若是不傳入 「title」,那麼全部處於 「ACTIVE」 狀態的 BLOG 都會返回;若是傳入了 「title」 參數,那麼就會對 「title」
一列進行模糊查找並返回對應的 BLOG 結果(細心的讀者可能會發現,「title」 的參數值須要包含查找掩碼或通配符字符)。
若是但願經過 「title」 和 「author」 兩個參數進行可選搜索該怎麼辦呢?首先,我想先將語句名稱修改爲改名副其實的名稱;接下來,只須要加入另外一個條件便可。dom
<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>
有時候,咱們不想使用全部的條件,而只是想從多個條件中選擇一個使用。針對這種狀況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
仍是上面的例子,可是策略變爲:傳入了 「title」 就按 「title」 查找,傳入了 「author」 就按 「author」 查找的情形。若二者都沒有傳入,
就返回標記爲 featured 的 BLOG(這多是管理員認爲,與其返回大量的無心義隨機 Blog,還不如返回一些由管理員精選的 Blog)。ide
<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>
前面幾個例子已經方便地解決了一個臭名昭著的動態 SQL 問題。如今回到以前的 「if」 示例,此次咱們將 「state = ‘ACTIVE’」 設置成動態條件,看看會發生什麼。測試
<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>
若是沒有匹配的條件會怎麼樣?最終這條 SQL 會變成這樣:code
SELECT * FROM BLOG WHERE
這會致使查詢失敗。若是匹配的只是第二個條件又會怎樣?這條 SQL 會是這樣:對象
SELECT * FROM BLOG WHERE AND title like ‘someTitle’
這個查詢也會失敗。這個問題不能簡單地用條件元素來解決。這個問題是如此的難以解決,以致於解決過的人不會再想碰到這種問題。
MyBatis 有一個簡單且適合大多數場景的解決辦法。而在其餘場景中,能夠對其進行自定義以符合需求。而這,只須要一處簡單的改動:blog
<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」 子句。並且,若子句的開頭爲 「AND」 或 「OR」,where 元素也會將它們去除。
若是 where 元素與你指望的不太同樣,你也能夠經過自定義 trim 元素來定製 where 元素的功能。好比,和 where 元素等價的自定義 trim 元素爲:索引
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
prefixOverrides 屬性會忽略經過管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子會移除全部 prefixOverrides 屬性中指定的內容,而且插入 prefix 屬性中指定的內容。
用於動態更新語句的相似解決方案叫作 set。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 關鍵字,並會刪掉額外的逗號(這些逗號是在使用條件語句給列賦值時引入的)。
來看看與 set 元素等價的自定義 trim 元素吧:
<trim prefix="SET" suffixOverrides=","> ... </trim>
注意,咱們覆蓋了後綴值設置,而且自定義了前綴值。
動態 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>
foreach 元素的功能很是強大,它容許你指定一個集合,聲明能夠在元素體內使用的集合項(item)和索引(index)變量。它也容許你指定開頭與結尾的字符串以及集合項迭代之間的分隔符。 這個元素也不會錯誤地添加多餘的分隔符,看它多智能! 提示 你能夠將任何可迭代對象(如 List、Set 等)、Map 對象或者數組對象做爲集合參數傳遞給 foreach。當使用可迭代對象或者數組時,index 是當前迭代的序號, item 的值是本次迭代獲取到的元素。當使用 Map 對象(或者 Map.Entry 對象的集合)時,index 是鍵,item 是值。 至此,咱們已經完成了與 XML 配置及映射文件相關的討論。下一章將詳細探討 Java API,以便你能充分利用已經建立的映射配置。