if
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
如果想可選地通過"title"和"author"兩個條件搜索,首先,改變語句的名稱讓它更具實際意義;然后只要加入另一個條件即可。
<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
MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。提供了"title"就按"title"查找,提供了"author"就按"author"查找,若兩者都沒有提供,就返回所有符合條件的BLOG
<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>
trim, where, set
MyBatis 有一個簡單的處理,這在90%的情況下都會有用。
<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 元素知道只有在一個以上的if條件有值的情況下才去插入"WHERE"子句。而且,若最后的內容是"AND"或"OR"開頭的,where 元素也知道如何將他們去除。
如果 where 元素沒有按正常套路出牌,我們還是可以通過自定義 trim 元素來定制我們想要的功能。比如,和 where 元素等價的自定義 trim 元素為:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
<select id="selectEmps" resultType="Emp">
<!-- SELECT * FROM emp e, dept d WHERE e.deptno=d.deptno -->
select * from emp e
<!-- <if test="ename != null"> where e.ename like #{ename} </if> -->
<trim prefix="where" prefixOverrides="and|or">
<if test="ename != null">
and e.ename like #{ename}
</if>
<if test="sal != null">
and e.sal > #{sal}
</if>
<if test="empnoList != null">
and e.empno in
<foreach collection="empnoList" item="empno" open="(" close=")"
separator=", " index="a">
#{empno}
</foreach>
</if>
</trim>
</select>
prefixOverrides 屬性會忽略通過管道分隔的文本序列(注意此例中的空格也是必要的)。它帶來的結果就是所有在 prefixOverrides 屬性中指定的內容將被移除,並且插入 prefix 屬性中指定的內容。
類似的用於動態更新語句的解決方案叫做 set。set 元素可以被用於動態包含需要更新的列,而舍去其他的。
<update id="updateEmp" parameterType="Emp">
update emp e
<set>
<if test="ename != null">
e.ename=#{ename},
</if>
<if test="job != null">
e.job=#{job},
</if>
<if test="mgr != null">
e.mgr=#{mgr},
</if>
<if test="hiredate != null">
e.hiredate=#{hiredate},
</if>
<if test="sal != null">
e.sal=#{sal},
</if>
<if test="comm != null">
e.comm=#{comm},
</if>
</set>
<where>
e.empno=#{empno}
</where>
</update>
這里,set 元素會動態前置 SET 關鍵字,同時也會消除無關的逗號,因為用了條件語句之后很可能就會在生成的賦值語句的后面留下這些逗號。
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>
foreach 元素的功能是非常強大的,它允許你指定一個集合,聲明可以用在元素體內的集合項和索引變量。它也允許你指定開閉匹配的字符串以及在迭代中間放置分隔符。這個元素是很智能的,因此它不會偶然地附加多余的分隔符。
注意 你可以將一個 List 實例或者數組作為參數對象傳給 MyBatis,當你這么做的時候,MyBatis 會自動將它包裝在一個 Map 中並以名稱為鍵。List 實例將會以"list"作為鍵,而數組實例的鍵將是"array"。
<select id="selectEmpsByList" resultType="Emp">
select e.*,sq_test.nextval from emp e
<trim prefix="where" prefixOverrides="and|or">
and e.empno in
<foreach collection="list" item="empno" open="(" close=")"
separator=", " index="a">
#{empno}
</foreach>
</trim>
</select>
