• Mybatis 动态SQL – 使用choose标签动态生成条件语句


    之前我们介绍了if,where标签的使用;本篇我们需要在if,where标签的基础上介绍如何使用Mybatis提供的choose标签动态生成条件语句。

    如果您对if,where标签动态生成条件语句不太了解,建议您先进行了解后再阅读本篇,可以参考:

    Mybatis 动态SQL – 使用if,where标签动态生成条件语句icon-default.png?t=N7T8https://blog.csdn.net/m1729339749/article/details/132627894

    一、数据准备

    这里我们直接使用脚本初始化数据库中的数据

    1. -- 如果数据库不存在则创建数据库
    2. CREATE DATABASE IF NOT EXISTS demo DEFAULT CHARSET utf8;
    3. -- 切换数据库
    4. USE demo;
    5. -- 创建用户表
    6. CREATE TABLE IF NOT EXISTS T_TEACHER(
    7. ID INT PRIMARY KEY COMMENT '教师编号',
    8. TEACHER_NAME VARCHAR(64) NOT NULL COMMENT '教师名称',
    9. DEPARTMENT VARCHAR(16) NOT NULL COMMENT '所属部门',
    10. BIRTH DATE NOT NULL COMMENT '出生年月',
    11. DEGREE VARCHAR(16) NOT NULL COMMENT '学历(ZK:专科, BK:本科, YJS:研究生, BS:博士)'
    12. );
    13. -- 插入用户数据
    14. INSERT INTO T_TEACHER(ID, TEACHER_NAME, DEPARTMENT, BIRTH, DEGREE)
    15. VALUES(1, '张三1', '001', '1990-06-12', 'BK'),
    16. (2, '李四1', '002', '1992-05-10', 'BK'),
    17. (3, '张三2', '003', '1988-01-15', 'YJS'),
    18. (4, '李四2', '001', '1979-03-10', 'BK'),
    19. (5, '李四3', '003', '1995-08-16', 'YJS');

    创建了一个名称为demo的数据库;并在库里创建了名称为T_TEACHER的教师表并向表中插入了数据

    二、环境搭建

    1、创建实体类

    在cn.horse.demo下创建TeacherInfo实体类:

    TeacherInfo类:

    1. package cn.horse.demo;
    2. import java.time.LocalDate;
    3. public class TeacherInfo {
    4. private Integer id;
    5. private String name;
    6. private String department;
    7. private LocalDate birth;
    8. private String degree;
    9. @Override
    10. public String toString() {
    11. StringBuilder stringBuilder = new StringBuilder();
    12. stringBuilder.append("{ ");
    13. stringBuilder.append("id: ");
    14. stringBuilder.append(this.id);
    15. stringBuilder.append(", ");
    16. stringBuilder.append("name: ");
    17. stringBuilder.append(this.name);
    18. stringBuilder.append(", ");
    19. stringBuilder.append("department: ");
    20. stringBuilder.append(this.department);
    21. stringBuilder.append(", ");
    22. stringBuilder.append("birth: ");
    23. stringBuilder.append(this.birth);
    24. stringBuilder.append(", ");
    25. stringBuilder.append("degree: ");
    26. stringBuilder.append(this.degree);
    27. stringBuilder.append(" }");
    28. return stringBuilder.toString();
    29. }
    30. }

    2、Mapper配置文件

    在resources的目录下新建TeacherInfoMapper.xml配置文件

    1. "1.0" encoding="UTF-8" ?>
    2. mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="cn.horse.demo.TeacherInfoMapper">
    6. <select id="findAll" parameterType="cn.horse.demo.TeacherInfoQuery" resultType="cn.horse.demo.TeacherInfo">
    7. SELECT
    8. ID,
    9. TEACHER_NAME name,
    10. DEPARTMENT,
    11. BIRTH,
    12. DEGREE
    13. FROM T_TEACHER
    14. <where>
    15. <if test="null != id and '' != id">
    16. AND ID = #{id}
    17. if>
    18. <if test="null != name and '' != name">
    19. AND TEACHER_NAME = #{name}
    20. if>
    21. <if test="null != department and '' != department">
    22. AND DEPARTMENT = #{department}
    23. if>
    24. <if test="null != degree and '' != degree">
    25. AND DEGREE = #{degree}
    26. if>
    27. where>
    28. select>
    29. mapper>

    3、引入配置文件

    在resources下新建mybatis-config.xml配置文件,并引入TeacherInfoMapper.xml配置文件

    1. "1.0" encoding="UTF-8" ?>
    2. configuration
    3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
    5. <configuration>
    6. <settings>
    7. <setting name="logImpl" value="JDK_LOGGING"/>
    8. settings>
    9. <environments default="development">
    10. <environment id="development">
    11. <transactionManager type="JDBC"/>
    12. <dataSource type="POOLED">
    13. <property name="driver" value="org.gjt.mm.mysql.Driver"/>
    14. <property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&useSSL=false&characterEncoding=utf8"/>
    15. <property name="username" value="root"/>
    16. <property name="password" value="horse"/>
    17. dataSource>
    18. environment>
    19. environments>
    20. <mappers>
    21. <mapper resource="demo/TeacherInfoMapper.xml" />
    22. mappers>
    23. configuration>

    4、会话工具类

    在cn.horse.demo包下新建SqlSessionUtils工具类

    1. package cn.horse.demo;
    2. import org.apache.ibatis.session.SqlSession;
    3. import org.apache.ibatis.session.SqlSessionFactory;
    4. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    5. import java.io.InputStream;
    6. import java.util.Objects;
    7. public class SqlSessionUtils {
    8. private static final SqlSessionFactory sqlSessionFactory;
    9. static {
    10. // 读取mybatis配置文件
    11. InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
    12. // 根据配置创建SqlSession工厂
    13. sqlSessionFactory = new SqlSessionFactoryBuilder()
    14. .build(inputStream);
    15. }
    16. /**
    17. * 开启会话
    18. * @return
    19. */
    20. public static SqlSession openSession() {
    21. return sqlSessionFactory.openSession();
    22. }
    23. /**
    24. * 关闭会话
    25. * @param sqlSession
    26. */
    27. public static void closeSession(SqlSession sqlSession) {
    28. if(Objects.nonNull(sqlSession)) {
    29. sqlSession.close();
    30. }
    31. }
    32. }

    5、JDK 日志系统配置

    在resources的目录下新建logging.properties配置文件

    1. handlers=java.util.logging.ConsoleHandler
    2. .level=INFO
    3. cn.horse.demo.TeacherInfoMapper.level=FINER
    4. java.util.logging.ConsoleHandler.level=ALL
    5. java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
    6. java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tT.%1$tL %4$s %3$s - %5$s%6$s%n

    在cn.horse.demo下新建JdkLogConfig类:

    JdkLogConfig类:

    1. package cn.horse.demo;
    2. import java.io.IOException;
    3. import java.io.InputStream;
    4. import java.util.logging.LogManager;
    5. public class JdkLogConfig {
    6. public JdkLogConfig() {
    7. try {
    8. InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("logging.properties");
    9. LogManager.getLogManager().readConfiguration(inputStream);
    10. } catch (IOException e) {
    11. throw new RuntimeException(e);
    12. }
    13. }
    14. }

    6、启动程序

    1. package cn.horse.demo;
    2. import org.apache.ibatis.session.SqlSession;
    3. import java.util.List;
    4. public class Main {
    5. public static void main(String[] args) {
    6. // 引入JDK日志配置
    7. System.setProperty("java.util.logging.config.class", "cn.horse.demo.JdkLogConfig");
    8. TeacherInfoQuery teacherInfoQuery = new TeacherInfoQuery();
    9. teacherInfoQuery.setId(1);
    10. teacherInfoQuery.setName("张三1");
    11. teacherInfoQuery.setDepartment("001");
    12. teacherInfoQuery.setDegree("BK");
    13. findAll("cn.horse.demo.TeacherInfoMapper.findAll", teacherInfoQuery);
    14. }
    15. private static void findAll(String statement, TeacherInfoQuery teacherInfoQuery) {
    16. SqlSession sqlSession = null;
    17. try {
    18. sqlSession = SqlSessionUtils.openSession();
    19. List teacherInfoList = sqlSession.selectList(statement, teacherInfoQuery);
    20. for (TeacherInfo teacherInfo: teacherInfoList) {
    21. System.out.println(teacherInfo);
    22. }
    23. } finally {
    24. SqlSessionUtils.closeSession(sqlSession);
    25. }
    26. }
    27. }

    执行后的结果如下:

    三、choose标签的使用

    在上面的运行结果中,我们可以看到执行的SQL语句:

    SELECT ID, TEACHER_NAME name, DEPARTMENT, BIRTH, DEGREE FROM T_TEACHER WHERE ID = ? AND TEACHER_NAME = ? AND DEPARTMENT = ? AND DEGREE = ?

    从SQL中我们可以看到条件语句中包含了ID、TEACHER_NAME、DEPARTMENT、DEGREE;而在实际的场景中ID是唯一的,ID作为条件时,其他的条件就显得比较多余,显然上面动态生成的条件语句是存在一些问题的,下面我们使用choose标签来解决此类问题:

    1. <select id="findAll" parameterType="cn.horse.demo.TeacherInfoQuery" resultType="cn.horse.demo.TeacherInfo">
    2. SELECT
    3. ID,
    4. TEACHER_NAME name,
    5. DEPARTMENT,
    6. BIRTH,
    7. DEGREE
    8. FROM T_TEACHER
    9. <where>
    10. <choose>
    11. <when test="null != id and '' != id">
    12. AND ID = #{id}
    13. when>
    14. <otherwise>
    15. <if test="null != name and '' != name">
    16. AND TEACHER_NAME = #{name}
    17. if>
    18. <if test="null != department and '' != department">
    19. AND DEPARTMENT = #{department}
    20. if>
    21. <if test="null != degree and '' != degree">
    22. AND DEGREE = #{degree}
    23. if>
    24. otherwise>
    25. choose>
    26. where>
    27. select>

    choose标签:标签中可以包含多个when标签、一个otherwise标签

    when标签:test属性值用作条件判断,与if标签的test属性一样;when标签可以多次使用

    otherwise标签:otherwise标签最多只能使用一次,并且只能作为choose标签内的最后一个标签。

    choose标签类似于Java中的switch语句,会依次判断when标签中的条件是否满足,直到找到满足条件的when标签,并将when标签中的条件语句拼装到SQL语句中并跳出choose标签;如果找不到满足条件的when标签,则将otherwise标签中的条件语句拼装到SQL语句中并跳出choose标签;

    1、示例:使用ID查询教师

    1. // 引入JDK日志配置
    2. System.setProperty("java.util.logging.config.class", "cn.horse.demo.JdkLogConfig");
    3. TeacherInfoQuery teacherInfoQuery = new TeacherInfoQuery();
    4. teacherInfoQuery.setId(1);
    5. teacherInfoQuery.setName("张三1");
    6. teacherInfoQuery.setDepartment("001");
    7. teacherInfoQuery.setDegree("BK");
    8. findAll("cn.horse.demo.TeacherInfoMapper.findAll", teacherInfoQuery);

    执行后的结果如下:

    结果分析:

    choose标签中,先判断第一个when标签条件是否满足,因为id为1,第一个条件满足,则将条件AND ID = #{id} 拼装到SQL语句中并跳出choose标签;所以执行的条件语句中只有ID = ? 条件

    2、示例:使用名称查询教师

    1. // 引入JDK日志配置
    2. System.setProperty("java.util.logging.config.class", "cn.horse.demo.JdkLogConfig");
    3. TeacherInfoQuery teacherInfoQuery = new TeacherInfoQuery();
    4. teacherInfoQuery.setName("张三1");
    5. findAll("cn.horse.demo.TeacherInfoMapper.findAll", teacherInfoQuery);

    执行后的结果如下:

    结果分析:

    choose标签中,先判断第一个when标签条件是否满足,因为id为null,第一个条件不满足,没有找到满足条件的when标签,则将otherwise标签中的条件语句拼装到SQL语句中并跳出choose标签(由于这里otherwise标签中的条件语句是动态SQL语句,则会执行动态SQL语句,执行后的结果AND TEACHER_NAME = #{name} 作为otherwise标签的内容);所以执行的条件语句中只有TEACHER_NAME = ? 条件

  • 相关阅读:
    组件化与插件化
    写一个基于C语言的保守垃圾回收器
    程序员的护城河:技术、创新还是沟通?
    我HTTP协议用的好好的,为什么还要用RPC协议?
    MATLAB | 官方举办的动图绘制大赛 | 第一周赛情回顾
    打造工业操作系统开源开放体系
    基于51单片机的简易电梯系统的设计
    Ukey连接虚拟前置机,浦银安盛基金用USB Server解决
    [ITIL]-ITIL4的服务管理关键概念
    VVC中图块划分结果在图像上显示(中间有一段没写完)
  • 原文地址:https://blog.csdn.net/m1729339749/article/details/132638515