11.动态sql

11.动态sql

什么是动态sql?

  • 动态 SQL 是 MyBatis 的强大特性之一。

  • 在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

    • if

    • choose (when, otherwise)

    • trim (where, set)

    • foreach

11.1 创建基础工程

第一步:创建数据库

 CREATE TABLE `blog`(
 `id` VARCHAR(50) NOT NULL COMMENT ‘博客id‘,
 `title` VARCHAR(100) NOT NULL COMMENT ‘博客标题‘,
 `author` VARCHAR(30) NOT NULL COMMENT ‘博客作者‘,
 `create_time` DATETIME NOT NULL COMMENT ‘创建时间‘,
 `views` INT(30) NOT NULL COMMENT ‘浏览量‘
 )ENGINE=INNODB DEFAULT CHARSET=utf8
 ?
 ?
 INSERT INTO blog VALUES(‘1‘,‘设计模式之单例模式‘,‘xuan‘,CURRENT_DATE,100);
 INSERT INTO blog VALUES(‘2‘,‘设计模式之工厂模式‘,‘xuan‘,CURRENT_DATE,200);
 INSERT INTO blog VALUES(‘3‘,‘设计模式之创建者模式‘,‘xuan‘,CURRENT_DATE,300);
 INSERT INTO blog VALUES(‘4‘,‘设计模式之抽象工厂模式‘,‘xuan‘,CURRENT_DATE,400);
 INSERT INTO blog VALUES(‘5‘,‘设计模式之责任链模式‘,‘xuan‘,CURRENT_DATE,1000);
 INSERT INTO blog VALUES(‘6‘,‘设计模式之桥接模式‘,‘xuan‘,CURRENT_DATE,50);
 ?

第二步:导入依赖、编写实体类,接口以及对应的配置文件

 <dependencies>
     <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
     <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.5.5</version>
     </dependency>
     <!--mysql数据库驱动-->
     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.20</version>
     </dependency>
     <!--junit测试-->
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.13</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.12</version>
     </dependency>
 </dependencies>
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class Blog implements Serializable {
 ?
     private String id;
     private String title;
     private String author;
     private Date createTime;
     private Integer views;
 }
 public interface BlogMapper {
 }
 <?xml version="1.0" encoding="utf-8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.xuan.mapper.BlogMapper">
 ?
 </mapper>

 

11.2 IF语句

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

第一步:编写mapper接口

 public interface BlogMapper {
 ?
     //通过if条件查询所需信息
     List<Blog> findBlogByIf(Map<String,Object> map)throws Exception;
 }

第二步:编写配置 加上if条件

 <select id="findBlogByIf" parameterType="map" resultType="blog">
    select * from blog where 1=1
     <if test="title != null">
        and title=#{title}
     </if>
     <if test="author != null">
        and author=#{author}
     </if>
 </select>

第三步:编写测试map为空返回全部

 @Test
 public void testFindBlogByIf() throws Exception {
     SqlSession sqlSession = MyBatisUtil.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
 ?
     Map<String, Object> map = new HashMap<>();
 
     List<Blog> blogs = mapper.findBlogByIf(map);
 ?
     for (Blog blog : blogs) {
         System.out.println(blog);
    }
 ?
     sqlSession.close();
 }
  • 测试结果

 Blog(id=1, title=设计模式之单例模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=100)
 Blog(id=2, title=设计模式之工厂模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=200)
 Blog(id=3, title=设计模式之创建者模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=300)
 Blog(id=4, title=设计模式之抽象工厂模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=400)
 Blog(id=5, title=设计模式之责任链模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=1000)
 Blog(id=6, title=设计模式之桥接模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=50)

第四步:测试加上if判断的语句

 @Test
 public void testFindBlogByIf() throws Exception {
     SqlSession sqlSession = MyBatisUtil.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
 ?
     Map<String, Object> map = new HashMap<>();
     map.put("title","设计模式之创建者模式");
     map.put("author","xuan");
 ?
     List<Blog> blogs = mapper.findBlogByIf(map);
 ?
     for (Blog blog : blogs) {
         System.out.println(blog);
    }
 ?
     sqlSession.close();
 }
  • 测试结果

 Blog(id=3, title=设计模式之创建者模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=300)

 

 

 

11.3 choose、when、otherwise语句

  • 有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。

 

第一步:编写mapper接口

 //通过choose条件查询所需信息
 List<Blog> findBlogByChoose(Map<String,Object> map)throws Exception;

第二步:编写配置文件(加入choose判断语句)

 <select id="findBlogByChoose" parameterType="map" resultType="blog">
    select * from blog where author="xuan"
    <choose>
        <when test="title != null">
            and title=#{title}
        </when>
        <when test="views != null">
            and views=#{views}
        </when>
        <otherwise>
            and id=1
        </otherwise>
    </choose>
 </select>

第三步:编写测试

 @Test
 public void testFindBlogByChoose() throws Exception {
     SqlSession sqlSession = MyBatisUtil.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
 ?
     Map<String, Object> map = new HashMap<>();
     //map.put("title","设计模式之创建者模式");
     map.put("views",100);
 ?
     List<Blog> blogs = mapper.findBlogByChoose(map);
 ?
     for (Blog blog : blogs) {
         System.out.println(blog);
    }
 ?
     sqlSession.close();
 }

--------------------------------------测试成功------------------------------------

 

 

11.4 trim、where、set语句

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

 <select id="findActiveBlogLike"
      resultType="Blog">
  SELECT * FROM BLOG
   <where>
     <if test="state != null">
          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>
  • set标签作用:set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

 <update id="updateAuthorIfNecessary">
  update Author
     <set>
       <if test="username != null">username=#{username},</if>
       <if test="password != null">password=#{password},</if>
       <if test="email != null">email=#{email},</if>
       <if test="bio != null">bio=#{bio}</if>
     </set>
  where id=#{id}
 </update>
  • trim标签:prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

 <trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
 </trim>
 <trim prefix="SET" suffixOverrides=",">
  ...
 </trim>

 

 

11.5 foreach语句

  • 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 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>
  • foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。

  • 它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符( open="(" separator="," close=")">)。这个元素也不会错误地添加多余的分隔符

完整的sql: select * from blog where id in (1 or 2 or 3)

 <select id="findByForEach" resultType="blog" parameterType="map">
    select * from blog
     <where>
         <foreach item="id" index="index" collection="ids"
                  open="(" separator="or" close=")">
            id = #{id}
         </foreach>
     </where>
 </select>

 

 

11.6 SQL片段

为什么要写SQL片段?

  • 主要是可以实现代码复用,有些重复的sql抽取出来重复使用。

  • sql标签: 通过id用来存放可重复利用的片段

  • include标签:refid用来引入sql标签中的语句

 <select id="findBlogByIf" parameterType="map" resultType="blog">
    select * from blog
     <where>
         <include refid="sql-if"></include>
     </where>
 </select>
 ?
 <sql id="sql-if">
     <if test="title != null">
        and title=#{title}
     </if>
     <if test="author != null">
        and author=#{author}
     </if>
 </sql>

 

 

 

 

11.动态sql

上一篇:MySQL字符集及校验规则


下一篇:postgresql存储过程