zoukankan      html  css  js  c++  java
  • 7、MyBatis动态SQL

    学习资源:动力节点《2020最新MyBatis教程【IDEA版】-MyBatis从入门到精通》



    动态 SQL,是指通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。 这里的条件判
    断使用的表达式为 OGNL 表达式。 常用的动态 SQL 标签有 <if>、<where>、<choose/>、<foreach> 等。

    MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。

    动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题。

    使用动态 SQL ,需要 Java 对象作为方法参数。


    在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则, XML 可能会出现解析出错问题。特别是对于小于号(<),在 XML 中是绝不能出现的。否则解析 mapper 文件会出错。

    实体符号表:

    原始符号 实体符号
    < &lt;
    > &gt;
    >= &gt;=
    <= &lt;=

    1、if

    使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。

    对于 <if> 标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片段拼接到其所在的 SQL 语句中。

    语法: <if test="条件表达式"> sql 语句片段 </if>

    使用实例:查询名字为 #{name} 并且年龄大于15岁的学生的信息,查询的前提条件:传入的参数 name 不为空,age>15。

    1. 接口方法:
    List<Student> selectStudentIf(Student student);  
    
    1. mapper 文件
    <select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student
        <!-- 小技巧 --->
        where 1=1
        <!-- <if:test="是使用方法参数 Java 对象的属性值作为判断条件"> -->
        <!-- #{} 也是使用方法参数 Java 对象的·属性值作为 sql 语句的参数 -->
        <if test="name != null and name !='' ">
        	and name = #{name}
        </if>
        <if test="age > 15 ">
        	or age &gt; #{age}
        </if>
    </select>
    

    3、测试方法

    @Test
    public void test(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        
        // 传入的对象是任意类型的,只要符合业务需求即可,此处使用 Student 的对象是因为懒
        Student params = new Student();
        params.setName("李四");
        params.setAge(15);
        List<Student> students = studentDao.selectStudentsIf(student);
        students.forEach(System.out::println);
    }
    

    <if/> 标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有 <if/> 条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,则SQL 出错。所以,在 where 后,需要添加永为真的子句 1=1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率。


    2、where

    如果使用 <where/> 标签, 在其后有查询条件时,可以自动添加上 where 子句;没有查询条件时,则不会添加 where 子句。

    注意:第一个 <if/> 标签中的 SQL 片断,可写可不写 and 或 or,因为 MyBatis 会将多余的 and 或 or 去掉;但之后的 <if/> 中 SQL 片断的 and 或 or,必须要求写上,否则 SQL 语句将拼接出错。

    <select id="findActiveBlogLike" resultType="Blog">
      SELECT * FROM BLOG
      <where>
        <if test="state != null">
            <!-- 此处也可以写 and 或 or -->
             state = #{state}
        </if>
        <if test="title != null">
            AND title like #{title}
        </if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        </if>
      </where>
    </select>
    

    3、foreach

    <foreach/> 标签用于实现对于方法参数是数组或集合中的元素的遍历,主要用在 sql 的 in 语句中。

    比如说,SQL中查询 id 是1001、1002、1003的学生的信息:

    select * from student where id in (1001,1002,1003);
    

    很容易想到,我们可以将这三个数据添加到一个集合中,将这个集合作为方法参数传给 mapper 文件,再从集合中遍历元素拼接为 完整的 sql 语句。

    现在先来模拟一下 MyBatis 对于该语句的拼接:

    @Test
    public void testfor(){
        List<Integer> list = new ArrayList<>();
        list.add(1001);
        list.add(1002);
        list.add(1003);
    
        //String sql="select * from student where id in (1001,1002,1003)";
        String sql="select * from student where id in";
    
        StringBuilder builder  = new StringBuilder("");
    
        //循环开始,字符串尾追加 (
        builder.append("(");
        for(Integer i:list){
            // 字符串尾追加 元素,
            builder.append(i).append(",");
        }
        builder.deleteCharAt(builder.length()-1);
        //循环结束,添加 )
        builder.append(")");
        sql = sql  + builder.toString();
        System.out.println("sql=="+sql);
    }
    

    <foreach> 的规范语法:

    <foreach collection="" item="自定义名称" open="" close="" separator="">
        #{item的自定义名称}
    </foreach>
    

    属性介绍:

    • collection:表示接口方法参数的类型,也即是表示要遍历的集合的类型
      • 数组,赋值为 array
      • 集合,赋值为 list
    • item:表示当前遍历到的集合成员,自定义名称
    • open:表示循环开始的字符
    • close:表示循环结束的字符
    • separator:集合成员之间的分隔符

    由之前的模拟,就可以很容易得出各个成员变量的值:

    • collection="list" 或 collection="array"
    • item="自定义名称"
    • open="("
    • close=")"
    • seperator=","

    3.1、遍历 List<简单类型>

    使用实例:查询 id 是 1002,1005,1006的学生的信息

    1. 接口方法
    List<Student> selectStudentForList(List<Integer> idList);
    
    1. mapper 文件
    <select id="selectStudentForList" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student
        <if test="list !=null and list.size > 0 ">
        	where id in
            <foreach collection="list" open="(" close=")" item="stuid" separator=",">
                <!-- 遍历简单类型,占位符使用item的值即可 -->
            	#{stuid}
            </foreach>
        </if>
    </select>
    
    1. 测试方法
    @Test
    public void testSelectForList() {
        List<Integer> list = new ArrayList<>();
        list.add(1002);
        list.add(1005);
        list.add(1006);
        List<Student> studentList = studentDao.selectStudentForList(list);
        studentList.forEach( stu -> System.out.println(stu));
    }
    

    3.2、遍历 List<对象类型>

    使用实例:查询 id 是 1002,1005,1006的学生的信息

    1. 接口方法
    List<Student> selectStudentForList2(List<Student> stuList);
    
    1. mapper 文件
    <select id="selectStudentForList2" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student
        <if test="list !=null and list.size > 0 ">
        	where id in
            <foreach collection="list" open="(" close=")" item="stuobject" separator=",">
            	#{stuobject.id}
            </foreach>
        </if>
    </select>
    
    1. 测试方法
    @Test
    public void testSelectForList2() {
        
        List<Student> list = new ArrayList<>();
        Student stu = new Student();
        stu.setId(1002);
        list.add(stu);
        stu = new Student();
        stu.setId(1005);
        stu = new Student();
        stu.setId(1006);
        list.add(stu);
        
        List<Student> studentList = studentDao.selectStudentForList2(list);
        studentList.forEach( stu -> System.out.println(stu));
    }
    

    4、choose、when、otherwise标签

    5、set

    6、trim

    7、SQL片段

    <sql/> 标签用于定义 SQL 片段,以便其它 SQL 标签复用。

    如果其它 SQL 标签需要复用 SQL 片段,只需要使用 <include/> 子标签进行引用即可。

    SQL 片段使用步骤:

    1. 定义一个 SQL 片段
    <sql id="自定义名称,唯一性">  
        可复用的 sql语句, 表名,字段等 
    </sql>
    
    1. 其他 SQL 标签使用 <include/> 进行引用
    <select id="" resultType="">
        <include refid="sql标签id的值" />
        剩余的sql语句部分
    </select>
    

    使用实例:

    <sql id="select*">
    	select id, name, age, email, from student
    </sql>
    
    <select id="selectStudentsIf" resultType="com.bjpowernode.domin,Student">
    	<include refid="select*" />
        <where>
        	<if test="name != null and name!='' ">
            	name=#{name}
            </if>
            <if test="age > 18">
                or age &gt; #{age}
            </if>
        </where>
    </select>
    
  • 相关阅读:
    BigDecimal 类型数据比较大小
    list排序,顺序,倒序
    springboot添加log4j日志配置log4j.xml生成日志文件
    mybatis使用@param("xxx")注解传参和不使用的区别
    jetty 插件启动指定端口号
    javaweb项目静态资源被拦截的解决方法
    day15 Python全局变量和局部变量
    阿里云操作视频
    Python基础视频
    马哥Python视频
  • 原文地址:https://www.cnblogs.com/sout-ch233/p/13608362.html
Copyright © 2011-2022 走看看