阅读 256

MyBatis 动态SQL

一、概述

  • 动态 SQL 是 MyBatis 的强大特性之一。
  • 通过动态 SQL,可以实现动态地拼接SQL语句,实现无需修改或创建多个标签,即可实现多种功能。

二、if

  • 只有当if标签内的条件满足,才会将if标签的内容拼接到SQL语句中
    <select id="selectBlogByIf" parameterType="map" resultType="blog">
        select id, name, author, release_date, view from blog
        <where>
            <if test="id != null">
                id = #{id}
            </if>
            <if test="view != null">
                and view >= #{view}
            </if>
        </where>
    </select>
    复制代码
      @Test
      public void selectBlogByIfTest() {
        try (SqlSession sqlSession = Utils.getSqlSession()) {
          BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
          Map map = new HashMap();
          map.put("id", 1);
          //map.put("view", 10);
          List<Blog> blogs = mapper.selectBlogByIf(map);
          blogs.forEach(logger::info);
        }
      }
    复制代码
    • 当map中只添加了id键,那就会生成语句where id = #{id};如果只添加了view键,那就生成语句where view = #{view};两个都添加了就生成语句where id = #{id} and view = #{view};如果啥都没加,那就啥筛选条件都没有

三、choose、when、otherwise

  • 实现从多个条件中选择一个,类似于Java的switch-case
    <select id="selectBlogByChoose" parameterType="map" resultType="blog">
        select id, name, author, release_date, view from blog
        <where>
            <choose>
                <when test="id != null">
                    id = #{id}
                </when>
                <when test="name != null">
                    name = #{name}
                </when>
            </choose>
        </where>
    </select>
    复制代码
      @Test
      public void selectBlogByChooseTest() {
        try (SqlSession sqlSession = Utils.getSqlSession()) {
          BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
          Map map = new HashMap();
          //map.put("id", 2);
          map.put("name", "10");
          List<Blog> blogs = mapper.selectBlogByChoose(map);
          blogs.forEach(logger::info);
        }
      }
    复制代码

四、trim、where、set

  • 为了实现无论是否增加筛选条件,都可以成功运行,可以将where提取出来作为标签,只有在where内的内容存在的时候,才添加where。详见以上例子。
  • where 元素只会在子元素返回任何内容的情况下才插入WHERE 子句。而且,若子句的开头为 ANDORwhere 元素也会将它们去除
  • set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="author != null">
                author = #{author},
            </if>
            <if test="release_date">
                name = #{releaseDate},
            </if>
            <if test="view != null">
                view = #{view},
            </if>
        </set>
        <where>
            <if test="id != null">
                id = #{id}
            </if>
        </where>
    </update>
    复制代码
      @Test
      public void updateBlogTest() {
        try (SqlSession sqlSession = Utils.getSqlSession()) {
          BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
          Map map = new HashMap();
          map.put("id", 1);
          map.put("view", 10);
          //map.put("author", "张三");
          map.put("name", "python");
          //map.put("releaseDate", LocalDate.now());
          int res = mapper.updateBlog(map);
          sqlSession.commit();
          if (res > 0)
            logger.info("修改成功");
          else
            logger.info("修改失败");
        }
      }
    复制代码
  • 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
    ...
    </trim>
    复制代码
    等效于set
    <trim prefix="SET" suffixOverrides=",">
      ...
    </trim>
    复制代码

    prefix 表示如果内容存在就在插入的在句子开头的内容;suffix 表示如果内容存在就在插入的在句子末尾的内容;prefixOverrides 表示如果内容的开头存在,就删除的部分;suffixOverrides 表示如果内容的末尾存在,就删除的部分。

五、foreach

  • 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
    <select id="selectBlogsByIds" resultType="blog" parameterType="list">
        select *
        from blog
        where id in
        <foreach item="id" collection="list" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
    复制代码

    item表示集合每个元素的名称,open为开始符号、close为结束符号,separator为分隔符

      @Test
      public void selectBlogsByIdsTest() {
        try (SqlSession sqlSession = Utils.getSqlSession()) {
          BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
          List<Blog> blogs = mapper.selectBlogsByIds(Arrays.asList(1, 2, 3));
          blogs.forEach(logger::info);
        }
      }
    复制代码
  • 批量插入
    int insertAll(@Param("users") List<User> users);
    复制代码
    <insert id="insertAll">
        insert user(id, name, address) values
        <foreach collection="users" item="user" separator=",">
          (#{user.id}, #{user.name}, #{user.address})
        </foreach>
    </insert>
    复制代码
      @Test
      public void testInsertAll() {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
          users.add(new User(i + 1, UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID().toString().substring(0, 10)));
        }
        try (SqlSession sqlSession = Utils.getSqlSession()) {
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          int res = mapper.insertAll(users);
          sqlSession.commit();
          if (res > 0)
            System.out.println("插入成功");
          else
            System.out.println("插入失败");
        }
      }
    复制代码

六、script

  • 要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素(注解开发配置,详见注解开发
    @Update({"<script>",
          "update blog",
          "<set>",
          "author = #{author}",
          "</set>",
          "where id = #{id}",
          "</script>"
      })
      int updateAuthorValues(@Param("author") String author, @Param("id") int id);
    复制代码

七、bind

  • bind在标签内允许创建一个变量,提前预处理好变量,再放进语句内拼接,常用于模糊查询
    <select id="selectBlogsByFuzzyQuery" resultType="blog" parameterType="string">
        <bind name="pattern" value="'%' + content + '%'"/>
        select *
        from blog
        where author like #{pattern}
    </select>
    复制代码

    将模糊查询包含content内容

      @Test
      public void selectBlogsByFuzzyQueryTest() {
        try (SqlSession sqlSession = Utils.getSqlSession()) {
          BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
          List<Blog> zhang = mapper.selectBlogsByFuzzyQuery("张");
          zhang.forEach(logger::info);
        }
      }
    复制代码
文章分类
后端
文章标签