上一章咱們已經講完了關於Mybatis的分頁用法,其實MyBatis 還具備的一個強大的特性之一一般是它的動態 SQL 能力。 若是你有使用 JDBC 或其餘 類似框架的經驗,你就明白要動態的串聯 SQL 字符串在一塊兒是十分糾結的,確保不能忘了空格或在列表的最後省略逗號。Mybatis中的動態 SQL 能夠完全處理這種痛苦。對於動態SQL,最通俗簡單的方法就是咱們本身在硬編碼的時候賦予各類動態行爲的判斷,而在Mybatis中,用一種強大的動態 SQL 語 言來改進這種情形,這種語言能夠被用在任意映射的 SQL 語句中。動態 SQL 元素和使用 JSTL 或其餘類似的基於 XML 的文本處理器類似。MyBatis 採用功能強大的基於 OGNL 的表達式來消除其餘元素。html
本章中咱們利用前幾章構建的實例,假設幾種應用狀況,經過實踐瞭解這幾種動態SQL標籤的用法,畢竟學習最快的途徑就是動手實踐~java
咱們經常使用的幾個節點元素有if,choose(when, otherwise),trim(where, if),foreach。真正使用下來我感受有點像XSLT的用法。詳細用法說明(點我)
git
(1)if 的用法github
還記得上一章中咱們有再ViisitMapper的分頁配置中看到if節點嗎,若是pageIndex>-1 and pageSize>-1的時候就加入相應的分頁SQL,不然就不添加(默認取所有),以下:
web
<select id="getListByPagenate" parameterType="PagenateArgs" resultType="Visitor"> select * from ( <include refid="getListSql" /> <include refid="orderBySql"/> ) t <!-- #{}表示參數化輸出,${}表示直接輸出不進行任何轉義操做,本身進行轉移 --> <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>
由於咱們的參數pageIndex與pageSize都是int值因此能夠這樣直接判斷,若是是對象實例咱們能夠利用null判斷來進行一些動態邏輯的控制,具體實際開發中就要看業務需求了。這裏我認爲要注意的是別十分順手的吧and寫成&&,這個在配置中不會被識別~。sql
(2)choose (when, otherwise)的用法session
choose when 主要在多個條件的狀況下只知足其中一個條件的應用場景中使用,例如這裏就構建一個query條件,分別傳遞id,name與createTime。假設咱們查詢Visitor表時,若是VisitorId有值則,使用Id查詢,若是VisitorName有值則採用VisitName查詢,以下,仍是在david.mybatis.demo.IVisitorOperation接口類中添加List<Visitor> getListChooseWhenDemo(BasicQueryArgs args)方法。在VisitorMapper中添加相應的的select節點配置:mybatis
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); /* * 基礎查詢 */ public Visitor basicQuery(int id); /* * 動態條件查詢(choose,when)實例 */ public List<Visitor> getListChooseWhenDemo(BasicQueryArgs args); /* * 動態條件查詢(where,if)實例 */ public List<Visitor> getListWhereDemo(BasicQueryArgs args); /* * 動態查詢(foreach)實例 */ public List<Visitor> getListForeachDemo(List<Integer> ids); }
<?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> <!-- 知足其中一個條件時候用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)的用法app
where關鍵詞的好處是在於,若是有相應的過濾條件的話,它知道在適當的時候插入where關鍵詞。並且它也知道在什麼時候該去掉相應的AND與OR的鏈接符,主要應對以下情景框架
<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>
不會由於全部條件不知足變爲
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE </select>
或者由於沒有知足第一個條件,單單知足後面的條件變成
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE AND title like ‘someTitle’ </select>
因此針對這種咱們能夠在創建choose when條件示例,一樣在IVisitorOperation接口類中加入相應的方法public List<Visitor> getListWhereDemo(BasicQueryArgs args),把VisitorMapper配置文件中的相對應配置加上去以下:
<?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的用法
在經常使用的動態SQL中咱們有個業務場景是要where id in 一大串的ID,像這種狀況咱們就能夠用到foreach啦,沒必要本身辛辛苦苦去拼接Id字符串啦。一樣的步驟仍是在IVisitorOperation接口類中加入相應的方法public List<Visitor> getListForeachDemo(List<Integer> ids),而後再對應的Mapper文件中配置上相應的節點元素信息,以下:
<?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循環條件 --> <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中創建相應的測試方法,Mybatis裏面的動態SQL也就完成啦,下面測試用的DemoRun方法
/* * 動態查詢foreach實例 */ 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); } } /* * 動態查詢where if實例 */ 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); } } } /* * 動態查詢choose when實例 */ 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); } } }
最後一章會講述,怎麼MybatisGenerator生成工具生成這些配置與文件~