上一章我們已經(jīng)講完了關(guān)于Mybatis的分頁用法,其實(shí)MyBatis 還具有的一個(gè)強(qiáng)大的特性之一通常是它的動(dòng)態(tài) SQL 能力。 如果你有使用 JDBC 或其他 相似框架的經(jīng)驗(yàn),你就明白要?jiǎng)討B(tài)的串聯(lián) SQL 字符串在一起是十分糾結(jié)的,確保不能忘了空格或在列表的最后省略逗號(hào)。Mybatis中的動(dòng)態(tài) SQL 可以徹底處理這種痛苦。對于動(dòng)態(tài)SQL,最通俗簡單的方法就是我們自己在硬編碼的時(shí)候賦予各種動(dòng)態(tài)行為的判斷,而在Mybatis中,用一種強(qiáng)大的動(dòng)態(tài) SQL 語 言來改進(jìn)這種情形,這種語言可以被用在任意映射的 SQL 語句中。動(dòng)態(tài) SQL 元素和使用 JSTL 或其他相似的基于 XML 的文本處理器相似。MyBatis 采用功能強(qiáng)大的基于 OGNL 的表達(dá)式來消除其他元素。
本章中我們利用前幾章構(gòu)建的實(shí)例,假設(shè)幾種應(yīng)用情況,通過實(shí)踐了解這幾種動(dòng)態(tài)SQL標(biāo)簽的用法,畢竟學(xué)習(xí)最快的途徑就是動(dòng)手實(shí)踐~
我們常用的幾個(gè)節(jié)點(diǎn)元素有if,choose(when, otherwise),trim(where, if),foreach。真正使用下來我感覺有點(diǎn)像XSLT的用法。詳細(xì)用法說明(點(diǎn)我)
(1)if 的用法
還記得上一章中我們有再ViisitMapper的分頁配置中看到if節(jié)點(diǎn)嗎,如果pageIndex>-1 and pageSize>-1的時(shí)候就加入相應(yīng)的分頁SQL,否則就不添加(默認(rèn)取全部),如下:
<select id="getListByPagenate" parameterType="PagenateArgs"
resultType="Visitor">
select * from (
<include refid="getListSql" /> <include refid="orderBySql"/>
) t <!-- #{}表示參數(shù)化輸出,${}表示直接輸出不進(jìn)行任何轉(zhuǎn)義操作,自己進(jìn)行轉(zhuǎn)移 -->
<if test="pageStart>-1 and pageSize>-1">
limit #{pageStart}, #{pageSize}
</if>
</select>
<sql id="getListSql">
select * from Visitor where
status>0
</sql>
<sql id="orderBySql">
order by ${orderFieldStr} ${orderDirectionStr}
</sql>
因?yàn)槲覀兊膮?shù)pageIndex與pageSize都是int值所以可以這樣直接判斷,如果是對象實(shí)例我們可以利用null判斷來進(jìn)行一些動(dòng)態(tài)邏輯的控制,具體實(shí)際開發(fā)中就要看業(yè)務(wù)需求了。這里我認(rèn)為要注意的是別十分順手的吧and寫成&&,這個(gè)在配置中不會(huì)被識(shí)別~。
(2)choose (when, otherwise)的用法
choose when 主要在多個(gè)條件的情況下只滿足其中一個(gè)條件的應(yīng)用場景中使用,例如這里就構(gòu)建一個(gè)query條件,分別傳遞id,name與createTime。假設(shè)我們查詢Visitor表時(shí),如果VisitorId有值則,使用Id查詢,如果VisitorName有值則采用VisitName查詢,如下,還是在david.mybatis.demo.IVisitorOperation接口類中添加List<Visitor> getListChooseWhenDemo(BasicQueryArgs args)方法。在VisitorMapper中添加相應(yīng)的的select節(jié)點(diǎn)配置:

修改后的IvisitorOperation
package david.mybatis.demo;
import java.util.List;
import david.mybatis.model.BasicQueryArgs;
import david.mybatis.model.PagenateArgs;
import david.mybatis.model.Visitor;
import david.mybatis.model.VisitorWithRn;
public interface IVisitorOperation {
/*
* 添加訪問者
*/
public int add(Visitor visitor);
/*
* 刪除訪問者
*/
public int delete(int id);
/*
* 更新訪問者
*/
public int update(Visitor visitor);
/*
* 查詢訪問者
*/
public Visitor query(int id);
/*
* 查詢List
*/
public List<Visitor> getList();
/*
* 分頁查詢List
*/
public List<Visitor> getListByPagenate(PagenateArgs args);
/*
* 分頁查詢List(包含Rownum)
*/
public List<VisitorWithRn> getListByPagenateWithRn(PagenateArgs args);
/*
* 基礎(chǔ)查詢
*/
public Visitor basicQuery(int id);
/*
* 動(dòng)態(tài)條件查詢(choose,when)實(shí)例
*/
public List<Visitor> getListChooseWhenDemo(BasicQueryArgs args);
/*
* 動(dòng)態(tài)條件查詢(where,if)實(shí)例
*/
public List<Visitor> getListWhereDemo(BasicQueryArgs args);
/*
* 動(dòng)態(tài)查詢(foreach)實(shí)例
*/
public List<Visitor> getListForeachDemo(List<Integer> ids);
}

choose-when-otherwise動(dòng)態(tài)條件配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="david.mybatis.demo.IVisitorOperation">
<resultMap type="Visitor" id="visitorRs">
<id column="Id" property="id" />
<result column="Name" property="name" />
<result column="Email" property="email" />
<result column="Status" property="status" />
<result column="CreateTime" property="createTime" />
</resultMap>
<sql id="getListSqlConditions">
select * from Visitor
</sql>
<!-- 滿足其中一個(gè)條件時(shí)候用choose when操作 -->
<select id="getListChooseWhenDemo" resultMap="visitorRs"
parameterType="BasicQueryArgs">
<include refid="getListSqlConditions" />
<where>
<if test="queryStatus>0">
status=#{queryStatus}
</if>
<choose>
<when test="queryId!=0">
and id=#{queryId}
</when>
<when test="queryName!=null">
and name like #{queryName}
</when>
<otherwise>
and createTime>= #{queryTime}
</otherwise>
</choose>
</where>
</select>
</mapper> (3)where if (trim)的用法
where關(guān)鍵詞的好處是在于,如果有相應(yīng)的過濾條件的話,它知道在適當(dāng)?shù)臅r(shí)候插入where關(guān)鍵詞。而且它也知道在何時(shí)該去掉相應(yīng)的AND與OR的連接符,主要應(yīng)對如下情景
<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>
不會(huì)因?yàn)樗袟l件不滿足變?yōu)?/p>
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
</select>
或者因?yàn)闆]有滿足第一個(gè)條件,單單滿足后面的條件變成
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
</select>
所以針對這種我們可以在建立choose when條件示例,同樣在IVisitorOperation接口類中加入相應(yīng)的方法public List<Visitor> getListWhereDemo(BasicQueryArgs args),把VisitorMapper配置文件中的相對應(yīng)配置加上去如下:

Where if動(dòng)態(tài)條件配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="david.mybatis.demo.IVisitorOperation">
<sql id="getListSqlConditions">
select * from Visitor
</sql>
<!-- 滿足條件的都加上去操作 -->
<select id="getListWhereDemo" resultMap="visitorRs"
parameterType="BasicQueryArgs">
<include refid="getListSqlConditions" />
<where>
<if test="queryStatus>0">
status>0
</if>
<if test="queryId>0">
and id=#{queryId}
</if>
<if test="queryName!=null">
and name like=#{queryName}
</if>
<if test="queryTime!=null">
and createTime>=#{queryTime}
</if>
</where>
<!--
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="queryStatus>0">
status>0
</if>
<if test="queryId>0">
and id=#{queryId}
</if>
<if test="queryName!=null">
and name like=#{queryName}
</if>
<if test="queryTime!=null">
and createTime>=#{queryTime}
</if>
</trim>
-->
</select>
</mapper>
(4)foreach的用法
在常用的動(dòng)態(tài)SQL中我們有個(gè)業(yè)務(wù)場景是要where id in 一大串的ID,像這種情況我們就可以用到foreach啦,不必自己辛辛苦苦去拼接Id字符串啦。同樣的步驟還是在IVisitorOperation接口類中加入相應(yīng)的方法public List<Visitor> getListForeachDemo(List<Integer> ids),然后再對應(yīng)的Mapper文件中配置上相應(yīng)的節(jié)點(diǎn)元素信息,如下:

Foreach動(dòng)態(tài)條件配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="david.mybatis.demo.IVisitorOperation">
<sql id="getListSqlConditions">
select * from Visitor
</sql>
<!-- Foreach循環(huán)條件 -->
<select id="getListForeachDemo" resultMap="visitorRs">
<include refid="getListSqlConditions"/>
where status>0 and id in
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
${item}
</foreach>
</select>
</mapper> 最后你只需要在DemoRun中建立相應(yīng)的測試方法,Mybatis里面的動(dòng)態(tài)SQL也就完成啦,下面測試用的DemoRun方法

DemoRun方法
/*
* 動(dòng)態(tài)查詢foreach實(shí)例
*/
public static void getListForeachDemo(List<Integer> ids) {
SqlSession session = MybatisUtils.getSqlSession();
IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class);
List<Visitor> ls = vOperation.getListForeachDemo(ids);
for (Visitor visitor : ls) {
System.out.println(visitor);
}
}
/*
* 動(dòng)態(tài)查詢where if實(shí)例
*/
public static void getListWhereCondition(int id, String name, Date createTime) {
name = name == "" ? null : name;
SqlSession session = MybatisUtils.getSqlSession();
BasicQueryArgs args = new BasicQueryArgs(id, name, createTime);
IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class);
List<Visitor> ls = vOperation.getListWhereDemo(args);
if (ls.size() == 0)
System.out.println("查無匹配!");
else {
for (Visitor visitor : ls) {
System.out.println(visitor);
}
}
}
/*
* 動(dòng)態(tài)查詢choose when實(shí)例
*/
public static void getListChooseWhenDemo(int id, String name, Date createTime) {
name = name == "" ? null : name;
SqlSession session = MybatisUtils.getSqlSession();
BasicQueryArgs args = new BasicQueryArgs(id, name, createTime);
IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class);
List<Visitor> ls = vOperation.getListChooseWhenDemo(args);
if (ls.size() == 0)
System.out.println("查無匹配!");
else {
for (Visitor visitor : ls) {
System.out.println(visitor);
}
}
} DemoRun方法運(yùn)行結(jié)果

最后一章會(huì)講述,怎么MybatisGenerator生成工具生成這些配置與文件~