動(dòng)態(tài)SQL
MyBatis還有一個(gè)方便的功能就是動(dòng)態(tài)SQL,可以根據(jù)條件智能生成SQL語(yǔ)句。這里的例子全部來(lái)自MyBatis文檔。
if標(biāo)簽
下面這個(gè)例子使用了MyBatis的if元素,在標(biāo)題不為空的情況下在查詢(xún)結(jié)果中包含標(biāo)題的查詢(xún)。
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
where/trim/set標(biāo)簽
如果需要在多個(gè)情況中包含某一個(gè)查詢(xún)條件。可以向下面這樣,使用choose、when、otherwise。如果使用過(guò)JSTL的話(huà),會(huì)發(fā)現(xiàn)這和JSTL的條件標(biāo)簽非常類(lèi)似。
<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>
對(duì)于下面這個(gè)例子,如果state為空,無(wú)法生成合法的SQL語(yǔ)句。
<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>
MyBatis自然也有相應(yīng)的解決辦法。就是使用where標(biāo)簽改寫(xiě)。where標(biāo)簽非常智能。如果標(biāo)簽內(nèi)部沒(méi)有合適的語(yǔ)句,where標(biāo)簽就不會(huì)生成任何東西,防止出現(xiàn)錯(cuò)誤語(yǔ)句。
<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>
有時(shí)候where標(biāo)簽還不能滿(mǎn)足需求。這時(shí)候還可以使用trim標(biāo)簽進(jìn)行更高級(jí)的定制。trim標(biāo)簽中的prefix和suffix屬性會(huì)被用于生成實(shí)際的SQL語(yǔ)句,會(huì)和標(biāo)簽內(nèi)部的語(yǔ)句拼接。如果語(yǔ)句的前面或后面遇到prefixOverrides或suffixOverrides屬性中指定的值,MyBatis會(huì)自動(dòng)將它們刪除。在指定多個(gè)值的時(shí)候,別忘了每個(gè)值后面都要有一個(gè)空格,保證不會(huì)和后面的SQL連接在一起。下面這個(gè)例子和where標(biāo)簽完全等效。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
還有一個(gè)set標(biāo)簽用于智能執(zhí)行更新語(yǔ)句。
<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>
與它等價(jià)的trim標(biāo)簽如下。
<trim prefix="SET" suffixOverrides=",">
...
</trim>
foreach標(biāo)簽
還有一個(gè)迭代標(biāo)簽可以生成一系列值,這個(gè)標(biāo)簽主要用于SQL的in語(yǔ)句后面。
<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>
bind標(biāo)簽
bind標(biāo)簽可以將非OGNL表達(dá)式值綁定到其中。下面的例子將結(jié)果映射中的值綁定到了OGNL表達(dá)式中,從而可以直接使用#{}
語(yǔ)法訪(fǎng)問(wèn)。
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
SQL構(gòu)造類(lèi)
有時(shí)候需要在Java代碼中生成SQL語(yǔ)句。如果我們直接編寫(xiě)的話(huà)會(huì)是一件非常麻煩的事情。由于Java不支持跨行字符串,所以我們要么在一行里面寫(xiě)一個(gè)非常非常長(zhǎng)的SQL語(yǔ)句,要么用加號(hào)拼接出一個(gè)笨拙的字符串。MyBatis提供了SQL構(gòu)造類(lèi),我們可以方便的使用這個(gè)類(lèi)構(gòu)造出SQL語(yǔ)句。
下面這幾個(gè)例子同樣來(lái)自于MyBatis文檔。SQL構(gòu)造類(lèi)有兩種用法:匿名類(lèi)和流式構(gòu)造。構(gòu)造完成之后,調(diào)用toString()
方法即可生成對(duì)應(yīng)的SQL語(yǔ)句。
// 匿名內(nèi)部類(lèi)
public String deletePersonSql() {
return new SQL() {{
DELETE_FROM("PERSON");
WHERE("ID = #{id}");
}}.toString();
}
// 流式構(gòu)造
public String insertPersonSql() {
String sql = new SQL()
.INSERT_INTO("PERSON")
.VALUES("ID, FIRST_NAME", "#{id}, #{firstName}")
.VALUES("LAST_NAME", "#{lastName}")
.toString();
return sql;
}
// 如果需要條件構(gòu)造,只能使用匿名類(lèi)方式,注意匿名類(lèi)要引用方法參數(shù)的話(huà),參數(shù)必須聲明為final的
public String selectPersonLike(final String id, final String firstName, final String lastName) {
return new SQL() {{
SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
FROM("PERSON P");
if (id != null) {
WHERE("P.ID like #{id}");
}
if (firstName != null) {
WHERE("P.FIRST_NAME like #{firstName}");
}
if (lastName != null) {
WHERE("P.LAST_NAME like #{lastName}");
}
ORDER_BY("P.LAST_NAME");
}}.toString();
}
public String deletePersonSql() {
return new SQL() {{
DELETE_FROM("PERSON");
WHERE("ID = #{id}");
}}.toString();
}