• MyBatis(五)动态Sql


    MyBatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。 

    1.if标签:

    if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行。

    如果我们没有去传输某些请求参数,而我在服务器中却获取了请求参数,获取的都是null。

    如果我们当前提交表单的,但是我们的文本框里面什么都没有输入,我们提交到服务器中的就是空字符串" "。

    在服务器中判断一下,null和"  ",没有设置条件。不等于null和" ",是设置了这个条件,就要把条件拼接到sql中。

    我们设置的实体类如下所示:

    1. package com.rgf.mybatis.pojo;
    2. public class Emp {
    3. private Integer empId;
    4. private String empName;
    5. private Integer age;
    6. private String gender;
    7. public Emp(Integer empId, String empName, Integer age, String gender) {
    8. this.empId = empId;
    9. this.empName = empName;
    10. this.age = age;
    11. this.gender = gender;
    12. }
    13. public Emp() {
    14. }
    15. public Integer getEmpId() {
    16. return empId;
    17. }
    18. public void setEmpId(Integer empId) {
    19. this.empId = empId;
    20. }
    21. public String getEmpName() {
    22. return empName;
    23. }
    24. public void setEmpName(String empName) {
    25. this.empName = empName;
    26. }
    27. public Integer getAge() {
    28. return age;
    29. }
    30. public void setAge(Integer age) {
    31. this.age = age;
    32. }
    33. public String getGender() {
    34. return gender;
    35. }
    36. public void setGender(String gender) {
    37. this.gender = gender;
    38. }
    39. @Override
    40. public String toString() {
    41. return "Emp{" +
    42. "empId=" + empId +
    43. ", empName='" + empName + '\'' +
    44. ", age=" + age +
    45. ", gender='" + gender + '\'' +
    46. '}';
    47. }
    48. }

    我们在utiles包里面封装的sqlsession如下所示:

    1. package com.rgf.mybatis.utils;
    2. import org.apache.ibatis.io.Resources;
    3. import org.apache.ibatis.session.SqlSession;
    4. import org.apache.ibatis.session.SqlSessionFactory;
    5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    6. import java.io.IOException;
    7. import java.io.InputStream;
    8. public class SqlSessionUtil {
    9. public static SqlSession getSqlSession() {
    10. SqlSession sqlSession = null;
    11. try {
    12. //获取核心配置文件的输入流
    13. //此时我们为捕获异常,这个时候要抛的话要抛到调用他的地方。
    14. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    15. //获取SqlSessionFactoryBuilder对象
    16. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    17. //获取SqlSessionFactory对象
    18. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    19. //获取Sqlsession对象
    20. sqlSession = sqlSessionFactory.openSession(true);
    21. } catch (IOException e) {
    22. e.printStackTrace();
    23. }
    24. return sqlSession;
    25. }
    26. }

    我们对于jdbc和核心配置的文件可以在之前的博客中进行查找。 

    我们创建接口DynamicSQLMapper,在其中设置该方法:

    1. /**
    2. * 根据条件查询员工信息
    3. * @param emp
    4. * @return
    5. */
    6. List getEmpByCondition(Emp emp);

    我们设置的映射文件DynamicSQLMapper,xml如下所示:

    1. "1.0" encoding="UTF-8" ?>
    2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. "com.rgf.mybatis.mapper.DynamicSQLMapper">

    我们设置的测试类如下所示:

    1. public class DynamicMapperTest {
    2. @Test
    3. public void testGetEmpByCondition(){
    4. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    5. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    6. Emp emp = new Emp(null,"张三",20,"男");
    7. List list = mapper.getEmpByCondition(emp);
    8. list.forEach(System.out::println);
    9. }
    10. }

    我们运行之后如下所示:

    if,通过test属性中的表达式判断标签中的内容是否有效(是否会拼接到sql中)

    2.where标签

    我们将测试修改如下所示:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"",20,"男");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    我们将张三修改为空字符串,运行之后如下所示:

     我们看到sql语句当empName不满足的时候,直接把下一条满足的跟在了where后面。(where后面不可以直接跟and)

    我们再将测试类修改如下所示:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"",null,"");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    我们运行之后如下所示:

    我们发现在条件都不满足的情况下,我们都不会拼接到where后面。我们的sql语句后面多出来一个where。

    我们的解决方法如下所示:

    解决方法一:

     我们将映射文件修改如下所示:

    1. <!--
    2. 动态SQL:
    3. 1.if,通过test属性中的表达式判断标签中的内容是否有效(是否会拼接到sql中 )
    4. -->
    5. <select id="getEmpByCondition" resultType="Emp">
    6. select * from t_emp where 1=1
    7. <if test="empName !=null and empName!=''">
    8. and emp_name=#{empName}
    9. </if>
    10. <if test="age != null and age!=''">
    11. and age=#{age}
    12. </if>
    13. <if test="gender!=null and gender!=''">
    14. and gender=#{gender}
    15. </if>
    16. </select>

    我们点击运行后如下所示:

    我们发现把当前所有数据都查找出来了。

     我们的测试类继续修改如下所示:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"",20,"男");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    我们运行后如下所示:

     解决方法二:

    我们的测试方法如下所示:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"张三",20,"男");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    我们将我们的映射文件修改如下所示:

    1. <select id="getEmpByCondition" resultType="Emp">
    2. select * from t_emp
    3. <where>
    4. <if test="empName !=null and empName!=''">
    5. emp_name=#{empName}
    6. </if>
    7. <if test="age != null and age!=''">
    8. and age=#{age}
    9. </if>
    10. <if test="gender!=null and gender!=''">
    11. and gender=#{gender}
    12. </if>
    13. </where>
    14. </select>

    我们将代码运行之后如下所示:

     如果我们将测试类进行修改:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"",20,"男");
    6. List<Emp> list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    我们将empName改为空字符串,此时第一条if语句不成立,我们进行运行如下所示:

     我们继续进行测试:将年龄改为null,我们如下所示:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"",null,"");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    我们运行之后如下所示:

    我们发现此时条件都不成立的时候,where标签没有任何功能。

    where标签的功能总结如下所示:

    a、若where标签中有条件成立,然后会自动生成where关键字

    b、会自动将where标签中内容前多余的and去掉,但是其中内容后多余的and无法去掉

    c、若where标签中没有任何一个条件成立,则where标签没有任何功能

     3、trim标签

    我们将测试类修改为如下所示:

    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"张三",20,"");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);
    8. }

    同时我们将映射文件里面的and放到内容后面,采用trim标签如下所示:

    其中的trim的属性如下所示: 

    其中有四个属性

    prefix:是在其中内容前面加上某些内容

    prefixOverrides:是在我们当前内容的前面去掉指定内容

    suffix:是在我们当前标签中内容的后面去添加指定内容

    suffixOverrides:是在我们当前标签中内容的后面去掉指定内容 

    我们运行之后如下所示:

    我们发现此时where有了,后面多余的and也没有了。 

    4、choose(父标签)、when(相当于if-else-if)、otherwise(相当于else)

    我们创建新的方法如下所示:

    1. /**
    2. * 使用choose查询员工信息
    3. * @param emp
    4. * @return
    5. */
    6. List getEmpByChoose(Emp emp);

    我们所写的映射文件如下所示:

     我们所写的测试类如下所示:

    1. @Test
    2. public void testGetEmpByChoose(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"张三",20,"");
    6. List list = mapper.getEmpByChoose(emp);
    7. list.forEach(System.out::println);
    8. }

    我们运行之后如下所示:

     我们发现只判断了emp_name,符合的话即停止进行判断。否则继续判断。

    choose、when、otherwise

    相当于java中的if.....else if....else

    when至少设置一个,otherwise最多设置一个

    5、foreach标签:(批量添加)

    collection:设置要循环的数组或集合

    item:用一个字符串表示数组或集合中的每一个数据

    separator:设置每次循环的数据之间的分隔符

    open:循环的所有内容以什么开始

    close:循环的所有内容以什么结束

     我们设置的接口方法如下所示:

    1. /**
    2. * 批量添加员工信息
    3. * @param emps
    4. */
    5. void insertMoreEmp(@Param("emps") List emps);

    我们设置的映射文件如下所示:

    获取自动递增的id使用:keyProperty和useGenerateKeys

    我们设置的测试类如下所示:

    1. @Test
    2. public void testInsertMoreEmp(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Emp emp1 = new Emp(null,"小明1",20,"男");
    6. Emp emp2 = new Emp(null,"小明2",20,"男");
    7. Emp emp3 = new Emp(null,"小明3",20,"男");
    8. List list = Arrays.asList(emp1, emp2, emp3);
    9. mapper.insertMoreEmp(list);
    10. }

    我们运行之后如下所示:

    我们打开数据库表,我们发现成功的添加进去了:

     6、foreach标签(批量删除):

    我们在mapper接口里面设置的方法如下所示:

    1. /**如果mapper接口方法的参数是一个list或者一个数组,mybatis都会把数据放在map中的,会以List为键,list集合为值,以这个参数为值放在map中。
    2. *如果是数组的话,mybatis也会把它放在map里面,以array为键,以当前的参数为值
    3. * 批量删除的功能
    4. * @param empIds
    5. */
    6. void deleteMoreEmp(@Param("empIds") Integer[]empIds);

    我们编写的映射文件如下所示:

    1. "deleteMoreEmp">
    2. delete from t_emp where emp_id in
    3. (
    4. "empIds " item="empId" separator=",">
    5. #{empId}
    6. )

    我们编写的测试类如下所示:

    1. @Test
    2. public void testDeleteMoreEmp(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    5. Integer [] empIds=new Integer[]{6,7};
    6. mapper.deleteMoreEmp(empIds);
    7. }

    我们运行之后如下所示:

     我们也可以将映射文件修改如下所示:

    1. "deleteMoreEmp">
    2. delete from t_emp where emp_id in
    3. "empIds " item="empId" separator="," open="(" close=")">
    4. #{empId}

    我们也可以用另一种方式:

    我们将映射文件修改如下所示:

    1. "deleteMoreEmp" >
    2. delete from t_emp where
    3. "empIds" item="empId" separator="or">
    4. emp_id=#{empId}

    7、sql标签

    我们的sql用法如下所示:

    1. 6、sql片段
    2. 可以记录一段sql,在需要用的地方使用include标签进行引用
    3. "empColumns">
    4. emp_id,emp_name,age,gender,dept_id
    5. select "empColumns"> from t_emp where 1=1
    6. -->

     我们在映射文件里面设计如下所示:

    1. "empColumns">
    2. emp_id,emp_name,age,gender,dept_id

    我们所使用的动态sql设计总结如下所示:

  • 相关阅读:
    gin实现event stream
    Elasticsearch的ON Error和ONOutOfMemoryError检查是两个与JVM(Java虚拟机)错误处理相关的引导检查
    图库 | 图计算的适用场景有哪些?
    layui的一些问题
    出差学小白知识No5:|Ubuntu上关联GitLab账号并下载项目(ssh key配置)
    idea2021+Activiti【最完整笔记一(基础使用)】
    C#学习系列之UDP同端口收发问题
    【k8s源码篇之Informer篇2】理解Informer内部的运行逻辑
    银河麒麟Telnet远程登录
    resetFields()报错
  • 原文地址:https://blog.csdn.net/weixin_59448049/article/details/127516614