Mybatis---動態SQL詳解(四)
(一)動態SQL簡介
使用JDBC對資料庫進行操作,通常需要根據需求手動的拼接SQL或重新編寫SQL語句,這是一項非常無聊和麻煩的操作,但是Mybatis提供了對SQL語句動態組裝的功能,恰好解決這一項麻煩的操作。
參考: Mybatis官方文件
Mybatis動態SQL語句中的主要元素
元素 | 說明 |
---|---|
<if> | 用於單條件分支判斷 |
<choose> <when> <otherwise> | 用於多條件分支判斷,類似Java中的switch語句 |
<where> <trim><set> | 輔助元素用於處理sql拼裝、特殊字元等問題 |
<foreach> | 迴圈語句用於in關鍵字列舉條件中 |
<bind> | 從OGNL表示式中建立一個變數將其繫結到上下文,用於模糊查詢 |
專案結構:
1.<if>元素
如果有多個<if test=”表示式”>元素,且test右邊的表示式為true,則SQL語句進行動態組裝。
例項演示
比如查詢客戶資訊,可以按使用者名稱或職位單欄位查詢,也可以使用者名稱和職位組合查詢(SQL動態組裝條件)
01.在CustomerMapper.xml中編寫動態SQL語句
<?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">
<!-- namespace+id確定一條SQL語句 -->
<mapper namespace="com.wang.mapper.CustomerMapper">
<select id="findCustomerByNameAndJobs"
parameterType ="com.wang.po.Customer"
resultType="com.wang.po.Customer">
select*from t_customer where 1=1
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</if>
<!--jobs表示Customer物件的屬性不為空-->
<if test="jobs!=null and jobs!=''">
and jobs=#{jobs}
</if>
</select>
</mapper>
02.在mybatis-config.xml檔案中引入CustomerMapper.xml檔案
<mappers>
<mapper resource="com/wang/mapper/CustomerMapper.xml" />
</mappers>
03.建立測試類MybatisTest.java
@Test
public void findCustomersByNameAndJobs() {
// 第一次查詢會話
SqlSession sqlSession = MybatisUtils.getSession();
Customer customer = new Customer();
// 為customer物件屬性設值,Mapper.xml使用OGNL可以檢測username是否設值
customer.setUsername("李四");
customer.setJobs("程式設計師");
List<Customer> customers = sqlSession.selectList("com.wang.mapper.CustomerMapper.findCustomerByNameAndJobs", customer);
for (Customer customer1 : customers) {
System.out.println(customer1);
}
sqlSession.close();
}
結果
01.當只在使用者名稱輸入框中輸入李四時:SQL語句只組裝username欄位條件
DEBUG [main] - ==> Preparing: select*from t_customer where 1=1 and
username like concat('%',?,'%')
DEBUG [main] - ==> Parameters: 李四(String)
DEBUG [main] - <== Total: 1
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]
02.當只在職業文字框輸入程式設計師時:SQL語句只組裝jobs欄位條件
DEBUG [main] - ==> Preparing: select*from t_customer where 1=1 and jobs=?
DEBUG [main] - ==> Parameters: 程式設計師(String)
DEBUG [main] - <== Total: 1
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]
03.同時在使用者和職業文字框輸入李四和程式設計師時:SQL組裝username和jobs兩個條件
DEBUG [main] - ==> Preparing: select*from t_customer where 1=1
and username like concat('%',?,'%') and jobs=?
DEBUG [main] - ==> Parameters: 李四(String), 程式設計師(String)
DEBUG [main] - <== Total: 1
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]
2.<choose><when><otherwise>元素
<choose><when><otherwise>元素類似Java中switch語句,滿足其中的一個條件即可實現SQL動態組裝。
例項演示
比如:01.使用者名稱不為空只能使用使用者名稱查詢。02.職業不為空只能使用職業來查詢,03.使用者名稱和職業都為空,那麼只能按電話號碼查詢。
01.在CustomerMapper.xml中編寫動態SQL語句
<select id="findCustomerByNameOrJobs"
parameterType="com.wang.po.Customer"
resultType="com.wang.po.Customer">
select*from t_customer where 1=1
<choose>
<when test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</when>
<!--jobs表示Customer物件的屬性不為空 -->
<when test="jobs!=null and jobs!=''">
and jobs=#{jobs}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
</select>
02.在mybatis-config.xml檔案中引入CustomerMapper.xml檔案
<mappers>
<mapper resource="com/wang/mapper/CustomerMapper.xml" />
</mappers>
03.建立測試類MybatisTest.java
@Test
public void findCustomersByNameOrJobs() {
// 第一次查詢會話
SqlSession sqlSession = MybatisUtils.getSession();
Customer customer = new Customer();
// 為customer物件屬性設值,Mapper.xml使用OGNL可以檢測username是否設值
customer.setUsername("李四");
customer.setJobs("程式設計師");
List<Customer> customers = sqlSession.selectList("com.wang.mapper.CustomerMapper.findCustomerByNameOrJobs", customer);
for (Customer customer1 : customers) {
System.out.println(customer1);
}
sqlSession.close();
}
結果:
注意:假設同時輸入李四和程式設計師,SQL語句根據CustomerMapper.xml中
username和jobs配置先後決定動態組裝哪個欄位。
比如CustomerMapper.xml中先配置
<when test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</when>所以先先判斷username,即先判斷使用者名稱
01.出入使用者名稱為李四,職業為程式設計師SQL語句動態組裝為以下形式:
DEBUG [main] - ==> Preparing: select*from t_customer
where 1=1 and username like concat('%',?,'%')
DEBUG [main] - ==> Parameters: 李四(String)
DEBUG [main] - <== Total: 1
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]
02.使用者名稱和職業都不輸入SQL語句動態組裝為以下形式:
DEBUG [main] - ==> Preparing: select*from t_customer where 1=1
and phone is not null
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 3
Customer [id=1, username=張三, jobs=學生, phone=183999999]
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]
Customer [id=3, username=王五, jobs=醫生, phone=183888888]
3.<where>、<trim> 元素用來代替”where 1=1”
01.<where> 的使用
<select id="findCustomerByNameOrJobs"
parameterType="com.wang.po.Customer"
resultType="com.wang.po.Customer">
select*from t_customer
<where>
<choose>
<when test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</when>
<!--jobs表示Customer物件的屬性不為空 -->
<when test="jobs!=null and jobs!=''">
and jobs=#{jobs}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
</where>
</select>
02.<trim> 的使用
屬性 | 說明 |
---|---|
prefix | 表示使用where連線後面的sql |
prefixOverrides | 去除特殊字元。比如sql中的and和or等 |
<select id="findCustomerByNameOrJobs"
parameterType="com.wang.po.Customer"
resultType="com.wang.po.Customer">
select*from t_customer
<trim prefix="where" prefixOverrides="and">
<choose>
<when test="username!=null and username!=''">
and username like concat('%',#{username},'%')
</when>
<!--jobs表示Customer物件的屬性不為空 -->
<when test="jobs!=null and jobs!=''">
and jobs=#{jobs}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
</trim>
</select>
4.<set> 元素代替SQL語句中的關鍵字set
<set> 元素的作用:動態的修改資料表中的欄位。比如Hebernate更新某個物件需要傳送所有欄位給持久層物件,把持久層的所有都更新了一遍。在開發過程中往往不需要把資料庫中的欄位全部更新一遍,因此我們使用Mybatis動態SQL語句更新需要更新的資料,這樣增強了程式執行效率。
01.<set> 的使用(一條動態SQL可以在多個場景引用)
例項演示
<update id="updateCustomer" parameterType="com.wang.po.Customer">
update t_customer
<set>
<if test="username !=null and username!=''">
username=#{username},
</if>
<if test="jobs !=null and jobs!=''">
jobs=#{jobs},
</if>
<if test="phone !=null and phone!=''">
phone=#{phone}
</if>
<if test="address !=null and address!=''">
address=#{address}
</if>
</set>
where id=#{id}
</update>
@Test
public void updateCustomersByNameOrJobsOrAddress() {
// 第一次查詢會話
SqlSession sqlSession = MybatisUtils.getSession();
Customer customer = new Customer();
// 為customer物件屬性設值,Mapper.xml使用OGNL可以檢測username是否設值
customer.setId(3);
//修改id為3的電話號碼
customer.setPhone("183121212");
customer.setJobs("程式設計師");
int rows=sqlSession.update("com.wang.mapper.CustomerMapper.updateCustomer", customer);
if(rows>0) {
System.out.println("更新成功!");
}else {
System.out.println("更新失敗!");
}
sqlSession.commit();
sqlSession.close();
}
結果
注:修改兩個欄位
DEBUG [main] - ==> Preparing: update t_customer SET jobs=?, phone=?
where id=?
DEBUG [main] - ==> Parameters: 程式設計師(String), 183121212(String), 3(Integer)
DEBUG [main] - <== Updates: 1
更新成功!
5.<foreach> 元素用於查詢一個指定範圍類資料
<foreach> 元素主要屬性
屬性 | 說明 |
---|---|
item | 表示迴圈獲取的元素 |
index | 表示當前元素在集合中的位置(即集合中的索引) |
collection | 配置查詢引數的型別(注:引數型別要小寫) |
open和close | 配置的是以什麼符號將這些集合元素包裝起來 |
separator | 使用逗號分割元素 |
比如:查詢t_customer表中id小於或等於2的使用者資訊
01.CustomerMapper.xml
<select id="findCustomerByIds" parameterType="List"
resultType="com.wang.po.Customer">
select*from t_customer where id in
<foreach item="id" index="index" collection="list" open="("
separator="," close=")">#{id}</foreach>
</select>
02.MybatisTest.java
@Test
public void findCustomerByIds() {
SqlSession sqlSession = MybatisUtils.getSession();
// 建立List集合物件用來儲存id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
List<Customer> customers = sqlSession.selectList("com.wang.mapper.CustomerMapper" + ".findCustomerByIds", ids);
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
結果
DEBUG [main] - ==> Preparing: select*from t_customer where id in ( ? , ? )
DEBUG [main] - ==> Parameters: 1(Integer), 2(Integer)
DEBUG [main] - <== Total: 2
Customer [id=1, username=張三, jobs=學生, phone=183999999]
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]
6.<bind> 元素等價於concat()函式都是用於模糊查詢
比如:模糊查詢t_customer資料表使用者名稱為“李”的客戶資訊
01.CustomerMapper.xml
<select id="findCustomerByIds" parameterType="com.wang.po.Customer"
resultType="com.wang.po.Customer">
<!-- value:填寫Customer中的username屬性 -->
<bind name="name" value="'%'+username+'%'"/>
select*from t_customer where username like #{name}
</select>
02.MybatisTest.java
@Test
public void findCustomerByName() {
SqlSession sqlSession = MybatisUtils.getSession();
Customer customer=new Customer();
customer.setUsername("李");
List<Customer> customers = sqlSession.selectList("com.wang.mapper."
+ "CustomerMapper" + ".findCustomerByIds", customer);
for (Customer customer1 : customers) {
System.out.println(customer1);
}
sqlSession.close();
}
結果
DEBUG [main] - ==> Preparing: select*from t_customer where username like ?
DEBUG [main] - ==> Parameters: %李%(String)
DEBUG [main] - <== Total: 1
Customer [id=2, username=李四, jobs=程式設計師, phone=183666666]