• Mybatis动态sql全面详解


    写在前面

    动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

    CDATA

    在使用MyBatis过程中,有时我们的SQL是写在XML 映射文件中,如果写的SQL中有一些特殊的字符的话,在解析XML文件的时候会被当做XML自身元素,但我们不希望如此操作,所以我们要使用来解决。

    <select id="gtBlogs" resultType="Blog">
      <![CDATA[
        select * from t_blog where id < #{blogId}
      ]]>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    sql+include

    <sql id="extraSql">
    	`id`, `name`, `remark`, `create_by`, `create_at`, `update_by`, `update_at`
    </sql>
    
    <select id="selectOne" resultType="Employee">
        select <include refid="extraSql"></include> from employee where emp_id = #{empId}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    sql标签可以抽取sql片段,然后使用include标签将指定id的sql片段插入。

    if

    if标签:主要用于基本的if判断

    OGNL 的表达式

    JSP是用OGNL表达式进行解析的,mybatis的xml文件也是是用OGNL表达式解析。

    其中 test 的表达式是基于OGNL 的表达式,语法规则也是OGNL的语法规则。
    OGNL官方表达式手册:https://commons.apache.org/proper/commons-ognl/language-guide.html

    注:在test中无法使用<= 等符号可以使用 lte 代替
    < :lt
    <=:lte
    >:gt
    >=:gte

    <! -- trim()可以表示去除首位空格 -- >
    <if test='order != null and "DESC".equalsIgnoreCase(order.trim())'>
      xxxx
    </if>
    
    • 1
    • 2
    • 3
    • 4

    if用于where

    可以动态拼接sql条件。

    <select id="findOne" resultType="Blog">
      SELECT * FROM BLOG
      WHERE state = 'ACTIVE'
      <if test="title != null and title != ''">
        AND title = #{title}
      </if>
      <if test="author != null and author.name != null">
        AND author_name like #{author.name}
      </if>
      <if test="age ==null or age ==''">  
          AND AGE = #{student.age}
      </if>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    if用于set

    可以按需更新需要个更新的字段。

    <update id="updateSqlSet">
        update demo_user
            <set>
                <if test="name !=null"> name=#{name}, 
                <if test="age !=null">  age = #{age}, 
                <if test="sex !=null">  sex = #{sex} 
            </set>
            where id = #{id}
    </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    choose、when、otherwise

    有点类似java中的switch,也有点像if-else

    <select id="findOne" resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
      <choose>
        <when test="title != null">
          AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
          AND author_name like #{author.name}
        </when>
        <otherwise>
          AND featured = 1
        </otherwise>
      </choose>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    where

    where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

    <select id="findOne" resultType="Blog">
      SELECT * FROM BLOG
      <where>
        <if test="state != null">
            AND 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    set

    set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

    <update id="updateOne">
      update Author
        <set>
          <if test="username != null">username=#{username},
          <if test="password != null">password=#{password},
          <if test="email != null">email=#{email},
          <if test="bio != null">bio=#{bio}
        </set>
      where id=#{id}
    </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    trim

    trim可以替代where和set。

    trim的属性:

    • prefix:指定要动态添加的前缀
    • suffix:指定要动态添加的后缀
    • prefixOverrides:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
    • suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值

    trim替换where

    <select id="selectDatas" resultType="Employee">
        select * from employee
        <trim prefix="WHERE" prefixOverrides="AND|OR">
            <if test="empId != null">
                AND emp_id>#{empId}
            </if>
            <if test="empSalary != null">
                AND emp_salary>#{empSalary}
            </if>
        </trim>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    trim替换set

    <update id="updateOne">
      update Author
        <trim prefix="SET" suffixOverrides=",">
          <if test="username != null">username=#{username},
          <if test="password != null">password=#{password},
          <if test="email != null">email=#{email},
          <if test="bio != null">bio=#{bio}
        </trim>
      where id=#{id}
    </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    bind

    bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。

    <select id="selectBlogsLike" resultType="Blog">
      <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
      SELECT * FROM BLOG
      WHERE title LIKE #{pattern}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    foreach

    foreach常用于对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

    <select id="selectPostIn" resultType="domain.blog.Post">
      SELECT *
      FROM POST P
      WHERE ID in
      <foreach item="item" index="index" collection="list"
          open="(" separator="," close=")">
            #{item}
      </foreach>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

    你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

    • collection属性: 表示要遍历的对象,如果要遍历的参数使用@Param注解取名了就使用该名字,如果没有取名List,或者collection。
    • item属性: 表示遍历出来的元素,我们到时候要拼接SQL语句就得使用这个元素: 如果遍历出来的元素是POJO对象, 那么我们就通过 #{遍历出来的元素.POJO的属性} 获取数据;如果遍历出来的元素是简单类型的数据,那么我们就使用 #{遍历出来的元素} 获取这个简单类型数据
    • separator属性: 遍历出来的元素之间的分隔符
    • open属性: 在遍历出来的第一个元素之前添加前缀
    • close属性: 在遍历出来的最后一个元素之后添加后缀

    script

    要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。

        @Update({""})
        void updateAuthorValues(Author author);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    也可以在Dao的java中直接使用注解标注sql语句

    @Select("select * from t_job t where t.id = #{id}")
    JobModel getById(Long id);
    
    • 1
    • 2

    多数据库支持

    如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。

    <insert id="insert">
      <selectKey keyProperty="id" resultType="int" order="BEFORE">
        <if test="_databaseId == 'oracle'">
          select seq_users.nextval from dual
        </if>
        <if test="_databaseId == 'db2'">
          select nextval for seq_users from sysibm.sysdummy1"
        </if>
      </selectKey>
      insert into users values (#{id}, #{name})
    </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    3.Octree相关
    大学生抗击疫情感动人物最美逆行者网页设计作业 html抗疫专题网页设计 最美逆行者网页模板 致敬疫情感动人物网页设计制作
    Linux防火墙之iptables(上)
    query词权重, 搜索词权重计算
    高新技术企业的认定申请材料有哪些?
    LeetCode·每日一题·655.输出二叉树·DFS
    域用户设置壁纸后断网出现黑壁纸问题
    java的IO流+springboot+vue实现服务器的文件上传下载
    Mysql 通过binlog伪装master恢复数据库
    百亿级访问量,如何做缓存架构设计
  • 原文地址:https://blog.csdn.net/A_art_xiang/article/details/126048007