Java的MyBatis框架中對數據庫進行動態(tài)SQL查詢的教程
其實MyBatis具有的一個強大的特性之一通常是它的動態(tài) SQL 能力。 如果你有使用 JDBC 或其他 相似框架的經驗,你就明白要動態(tài)的串聯(lián) SQL 字符串在一起是十分糾結的,確保不能忘了空格或在列表的最后省略逗號。Mybatis中的動態(tài) SQL 可以徹底處理這種痛苦。對于動態(tài)SQL,最通俗簡單的方法就是我們自己在硬編碼的時候賦予各種動態(tài)行為的判斷,而在Mybatis中,用一種強大的動態(tài) SQL 語 言來改進這種情形,這種語言可以被用在任意映射的 SQL 語句中。動態(tài) SQL 元素和使用 JSTL 或其他相似的基于 XML 的文本處理器相似。MyBatis 采用功能強大的基于 OGNL 的表達式來消除其他元素。
我們常用的幾個節(jié)點元素有if,choose(when, otherwise),trim(where, if),foreach。真正使用下來我感覺有點像XSLT(文章后面會順帶提一下~)的用法。
(1)if 的用法
在ViisitMapper的分頁配置中,如果pageIndex>-1 and pageSize>-1的時候就加入相應的分頁SQL,否則就不添加(默認取全部),如下:
<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判斷來進行一些動態(tài)邏輯的控制,具體實際開發(fā)中就要看業(yè)務需求了。這里我認為要注意的是別十分順手的吧and寫成&&,這個在配置中不會被識別~。
(2)choose (when, otherwise)的用法
choose when 主要在多個條件的情況下只滿足其中一個條件的應用場景中使用,例如這里就構建一個query條件,分別傳遞id,name與createTime。假設我們查詢Visitor表時,如果VisitorId有值則,使用Id查詢,如果VisitorName有值則采用VisitName查詢,如下,還是在david.mybatis.demo.IVisitorOperation接口類中添加List<Visitor> getListChooseWhenDemo(BasicQueryArgs args)方法。在VisitorMapper中添加相應的的select節(jié)點配置:
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);
/*
* 動態(tài)條件查詢(choose,when)實例
*/
public List<Visitor> getListChooseWhenDemo(BasicQueryArgs args);
/*
* 動態(tài)條件查詢(where,if)實例
*/
public List<Visitor> getListWhereDemo(BasicQueryArgs args);
/*
* 動態(tài)查詢(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)的用法
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>
不會因為所有條件不滿足變?yōu)?/p>
<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的用法
在常用的動態(tài)SQL中我們有個業(yè)務場景是要where id in 一大串的ID,像這種情況我們就可以用到foreach啦,不必自己辛辛苦苦去拼接Id字符串啦。同樣的步驟還是在IVisitorOperation接口類中加入相應的方法public List<Visitor> getListForeachDemo(List<Integer> ids),然后再對應的Mapper文件中配置上相應的節(jié)點元素信息,如下:
<?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中建立相應的測試方法,Mybatis里面的動態(tài)SQL也就完成啦,下面測試用的DemoRun方法
/*
* 動態(tài)查詢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);
}
}
/*
* 動態(tài)查詢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);
}
}
}
/*
* 動態(tài)查詢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);
}
}
}
PS:關于OGNL
OGNL 是 Object-Graph Navigation Language 的縮寫,從語言角度來說:它是一個功能強大的表達式語言,用來獲取和設置 java 對象的屬性 , 它旨在提供一個更高抽象度語法來對 java 對象圖進行導航,OGNL 在許多的地方都有應用,例如:
作為 GUI 元素(textfield,combobox, 等)到模型對象的綁定語言。
數據庫表到 Swing 的 TableModel 的數據源語言。
web 組件和后臺 Model 對象的綁定語言 (WebOGNL,Tapestry,WebWork,WebObjects) 。
作為 Jakarata Commons BeanUtils 或者 JSTL 的表達式語言的一個更具表達力的替代語言。
另外,java 中很多可以做的事情,也可以使用 OGNL 來完成,例如:列表映射和選擇。 對于開發(fā)者來說,使用 OGNL,可以用簡潔的語法來完成對 java 對象的導航。通常來說: 通過一個“路徑”來完成對象信息的導航,這個“路徑”可以是到 java bean 的某個屬性,或者集合中的某個索引的對象,等等,而不是直接使用 get 或者 set 方法來完成。
相關文章
Java+Windows+ffmpeg實現(xiàn)視頻轉換功能
這篇文章主要為大家詳細介紹了Java+Windows+ffmpeg實現(xiàn)視頻轉換功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12
mybatis-plus批量更新updateBatchById問題
這篇文章主要介紹了mybatis-plus批量更新updateBatchById問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
Spring?Boot存在路徑遍歷漏洞CVE-2021-22118的問題解析
CVE-2021-22118?是一個在?Spring?Boot?中發(fā)現(xiàn)的漏洞,該漏洞關系到?Spring?Boot?的開發(fā)者工具(Devtools)中的遠程更新(Remote?Update)功能,這篇文章主要介紹了Spring?Boot存在路徑遍歷漏洞CVE-2021-22118,需要的朋友可以參考下2023-09-09

