Mybatis 對映檔案的 SQL 深入
阿新 • • 發佈:2018-11-09
1.1 概述
- Mybatis 的對映檔案中,有些時候業務邏輯複雜時,我們的 SQL是動態變化的。
- 把判斷放在對映檔案中,使用動態SQL標籤:<if>、<where>、 <foreach>、<sql>、<include>
1.2動態SQL之<if>標籤
我們根據實體類的不同取值,使用不同的 SQL 語句來進行查詢。比如在 id 如果不為空時可以根據 id查詢,如果 username 不同空時還要加入使用者名稱作為條件。這種情況在我們的
多條件組合查詢中經常會碰到。
- 需求: 根據id或者名稱查詢
- dao查詢方法
package com.sunny.dao; import com.sunny.entity.QueryVo; import com.sunny.entity.User; import java.util.List; /** * 使用者資料訪問介面 */ public interface IUserDao { //根據id或username條件查詢使用者列表 List<User> findByCondition(User user); //根據主鍵查詢實體類物件 User findById(int id); }
3.介面對映 IUserDao.xml
<?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名稱空間,用於定義是哪個類的對映檔案,這裡需要寫所對映介面的類全名--> <mapper namespace="com.sunny.dao.IUserDao"> <!--根據主鍵查詢實體類物件--> <select id="findById" resultType="com.sunny.entity.User" parameterType="int"> SELECT * FROM USER WHERE id = #{id} </select> 動態SQL <if> 條件判斷標籤 test屬性,用來判斷的表示式,返回boolean型別 test=" id != 0"這裡的id就是parameterType中User物件的id屬性 這裡的id也是獲取物件的id屬性值 <select id="findByCondition" resultType="com.sunny.entity.User"> SELECT * FROM USER WHERE 1=1 <if test="id != 0"> AND id = #{id} </if> <if test="username != null and username != ''"> and username like #{username} </if> </select> </mapper>
4.測試
import com.sunny.dao.IUserDao;
import com.sunny.entity.QueryVo;
import com.sunny.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class UserDaoTest {
InputStream in = null;
SqlSession sqlSession = null;
@Before
public void before() throws IOException {
//1.獲取主配置檔案的輸入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.建立資料庫連線工廠構建類
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//3.根據資料庫連線工廠構建類建立資料庫連線工廠
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
//4.根據資料庫連線工廠獲取資料庫連線SqlSession物件
sqlSession = sqlSessionFactory.openSession();
}
/**
* 根據主鍵查詢實體類物件
*/
@Test
public void findById(){
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
System.out.println(userDao.findById(51));
}
/**
* 根據id或username條件查詢使用者列表
*/
@Test
public void findByCondition() throws IOException, ParseException {
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setUsername("%張%");
user.setId(41);
List<User> userList = userDao.findByCondition(user);
userList.forEach(System.out::println);
}
@After
public void after() throws IOException {
//提交事務
sqlSession.commit();
//關閉資源
sqlSession.close();
in.close();
}
}
5.測試結果
1.3 動態SQL之<where>標籤
- 作用:通過<where>標籤拼接where條件,簡化where寫法。
<!--使用where標籤優化上面的where-->
<select id="findByCondition" resultType="com.sunny.entity.User">
SELECT * FROM USER
<where>
<if test="id != 0">
and id = #{id}
</if>
<if test="id != null and id !='' ">
and username like #{username}
</if>
</where>
</select>
1.4 動態標籤之foreach標籤
- 作用:遍歷引數值。
- 查詢需求:根據多個id查詢。
SELECT * FROM USER WHERE id=41 OR id=42
SELECT * FROM USER WHERE id IN (41,42)- 定義查詢擴充套件物件,封裝多個id值
package com.sunny.entity;
import java.util.List;
/**
* 當前QueryVo支援User物件的所有屬性查詢以及擴充套件屬性
*/
public class QueryVo extends User {
//條件:多個id
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
5.dao介面,對映
package com.sunny.dao;
import com.sunny.entity.QueryVo;
import com.sunny.entity.User;
import java.util.List;
/**
* 使用者資料訪問介面
*/
public interface IUserDao {
//根據多個id查詢使用者列表
List<User> findByCondition2(QueryVo queryVo);
}
<?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名稱空間,用於定義是哪個類的對映檔案,這裡需要寫所對映介面的類全名-->
<mapper namespace="com.sunny.dao.IUserDao">
<!--根據主鍵查詢實體類物件-->
<select id="findById" resultType="com.sunny.entity.User" parameterType="int">
SELECT * FROM USER WHERE id = #{id}
</select>
<!--根據多個id查詢使用者列表
目標:使用mybatis動態標籤foreach標籤實現sql,select * from user where id in(41,43)
foreach:用於迴圈遍歷
collection:用於遍歷的集合,必須時輸入型別的屬性
open:拼接SQL的開始部分
close:拼接SQL的結束部分
separator:迴圈拼接的分隔符號
item:要遍歷的元素(集合裡面的每個元素名字)
#{id}:佔位符的值,裡面id名字與item設定的名字保持一致
-->
<sql id="selectUser">
SELECT * FROM USER
</sql>
<select id="findByCondition2" resultType="com.sunny.entity.User" parameterType="com.sunny.entity.QueryVo">
<include refid="selectUser"></include>
<where>
<if test="ids!=null and ids.size()>0">
<foreach collection="ids" open=" id IN (" separator="," close=")" item="id">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
6.測試
import com.sunny.dao.IUserDao;
import com.sunny.entity.QueryVo;
import com.sunny.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class UserDaoTest {
InputStream in = null;
SqlSession sqlSession = null;
@Before
public void before() throws IOException {
//1.獲取主配置檔案的輸入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.建立資料庫連線工廠構建類
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//3.根據資料庫連線工廠構建類建立資料庫連線工廠
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
//4.根據資料庫連線工廠獲取資料庫連線SqlSession物件
sqlSession = sqlSessionFactory.openSession();
}
/**
* 根據多個id查詢使用者列表
* @throws IOException
*/
@Test
public void findByCondition2() throws IOException, ParseException {
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
QueryVo queryVO = new QueryVo();
List<Integer> ids = new ArrayList<>();
ids.add(42);
ids.add(47);
ids.add(45);
ids.add(46);
queryVO.setIds(ids);
List<User> userList = userDao.findByCondition2(queryVO);
userList.forEach(System.out::println);
}
@After
public void after() throws IOException {
//提交事務
sqlSession.commit();
//關閉資源
sqlSession.close();
in.close();
}
}
1.5mybatis中簡化編寫的SQL片段
- Sql 中可將重複的 sql 提取出來,使用時用 include 引用即可,最終達到 sql 重用的目的。我們先到 UserDao.xml 檔案中使用<sql>標籤,定義出公共部分。
<!--
sql標籤:定義SQL片段,抽取公用的SQL部分
include標籤: 用來引用sql片段
-->
<sql id="selectUser">
SELECT * FROM USER WHERE 1=1
</sql>
<select id="findByCondition2" parameterType="queryvo" resultType="user">
<!--引用SQL片段-->
<include refid="selectUser"></include>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id IN (" separator="," close=")" item="id">
#{id}
</foreach>
</if>
</select>
- 再通過<include>標籤的 refid 屬性的值就是<sql> 標籤定義 id 的取值。
注意:如果引用其它 mapper.xml 的 sql 片段,則在引用時需要加上 namespace,如下:
<include refid="namespace.sql 片段”/>