mybatis動態sql標籤的使用
trim, where, set
前面幾個例子已經合宜地解決了一個臭名昭著的動態 SQL 問題。現在考慮回到“if”示例,這次我們將“ACTIVE = 1”也設定成動態的條件,看看會發生什麼。
<selectid="findActiveBlogLike"resultType="Blog"> SELECT * FROM BLOG WHERE <iftest="state != null"> state = #{state} </if><iftest="title != null"> AND title like #{title}</if><iftest="author != null and author.name != null"> AND author_name like #{author.name} </if></select>
如果這些條件沒有一個能匹配上將會怎樣?最終這條 SQL 會變成這樣:
SELECT * FROM BLOG WHERE
這會導致查詢失敗。如果僅僅第二個條件匹配又會怎樣?這條 SQL 最終會是這樣:
SELECT * FROM BLOG WHERE AND title like ‘someTitle’
這個查詢也會失敗。這個問題不能簡單的用條件句式來解決,如果你也曾經被迫這樣寫過,那麼你很可能從此以後都不想再這樣去寫了。
MyBatis 有一個簡單的處理,這在90%的情況下都會有用。而在不能使用的地方,你可以自定義處理方式來令其正常工作。一處簡單的修改就能得到想要的效果:
<selectid="findActiveBlogLike"resultType="Blog"> SELECT * FROM BLOG <where><iftest="state != null"> state = #{state} </if><iftest="title != null"> AND title like #{title}</if><iftest="author != null and author.name != null"> AND author_name like #{author.name} </if></where></select>
where 元素知道只有在一個以上的if條件有值的情況下才去插入“WHERE”子句。而且,若最後的內容是“AND”或“OR”開頭的,where 元素也知道如何將他們去除。
如果 where 元素沒有按正常套路出牌,我們還是可以通過自定義 trim 元素來定製我們想要的功能。比如,和 where 元素等價的自定義 trim 元素為:
<trimprefix="WHERE"prefixOverrides="AND |OR "> ... </trim>
prefixOverrides 屬性會忽略通過管道分隔的文字序列(注意此例中的空格也是必要的)。它帶來的結果就是所有在 prefixOverrides 屬性中指定的內容將被移除,並且插入 prefix 屬性中指定的內容。
類似的用於動態更新語句的解決方案叫做 set。set 元素可以被用於動態包含需要更新的列,而捨去其他的。比如:
<updateid="updateAuthorIfNecessary"> update Author <set><iftest="username != null">username=#{username},</if><iftest="password != null">password=#{password},</if><iftest="email != null">email=#{email},</if><iftest="bio != null">bio=#{bio}</if></set> where id=#{id} </update>
這裡,set 元素會動態前置 SET 關鍵字,同時也會消除無關的逗號,因為用了條件語句之後很可能就會在生成的賦值語句的後面留下這些逗號。
若你對等價的自定義 trim 元素的樣子感興趣,那這就應該是它的真面目:
<trimprefix="SET"suffixOverrides=","> ... </trim>
注意這裡我們忽略的是字尾中的值,而又一次附加了字首中的值。