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 片段”/>