Mybatis-动态SQL-trim-choose-foreach

动态SQL

官方文档已经写的非常详细

动态Sql是指根据不同的条件生成不同的SQL语句

之前是手动拼接的,拼接sql语句是很麻烦的

四个标签:

  • if
  • choose(when,oherwise)
  • trim(where,set)
  • foreach

动态SQL环境搭建

  • 数据库
  • maven导包
  • 实体类
  • Mapper.xml
  • 核心配置文件
    • setting驼峰命名转换
  • 工具类
    • IDutils通过UUID实现随机ID

都是比较常用的套路

开始

  1. 创建数据库

    1. image-20200819215457734
  2. Maven导包

    1. <dependencies>
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>8.0.11</version>
          </dependency>
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.5.2</version>
          </dependency>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
              <scope>test</scope>
          </dependency>
          <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.17</version>
          </dependency>
          <dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
              <version>1.18.12</version>
          </dependency>
      </dependencies>
      
  3. 编写POJO实体类

    1. @Data
      @NoArgsConstructor
      @Alias("Blog")
      public class Blog {
          private String id;
          private String title;
          private String author;
          private Date createTime;
          //添加驼峰命名映射setting
          /*这个名字会映射成create_time*/
          /*mapUnderscoreToCamelCase*/
          private int views;
      }
      
  4. 编写接口以及接口映射

    1. 编写好实体类就写好对应的接口,接口写好写映射,然后把映射添加到核心配置文件中去

    2. public interface blogMapper {
          @Select("select * from blog")
          List<Blog> getblogs();
          int addBook(Blog blog);
      }
      
    3. 暂时写了两个接口,一个使用注解一个使用xml

    4. <?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.haoyun.dao.blogMapper">
      
          <insert id="addBook" parameterType="Blog">
              insert into mybatis.blog (id,title,author,create_time,views)
               values (#{id},#{title},#{author},#{createTime},#{views});
          </insert>
      
      </mapper>
      
    5. 因为添加了驼峰命名的设置,所以这里传递参数是填写的createTime

  5. 编写核心配置文件

    1. 使用的是外部配置文件

    2. driver  = com.mysql.cj.jdbc.Driver
      url= jdbc:mysql://localhost:3306/mybatis?useSSL=false
      -TRUE&useUnicode=true&characterEncoding=UTF-8
      username  =root
      password = 123456
      
    3. <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE configuration
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
          <!--引入外部配置文件-->
          <properties resource="db.properties"/>
          <settings>
              <setting name="mapUnderscoreToCamelCase" value="true"/>
          </settings>
          <typeAliases>
              <package name="com.haoyun.POJO"/>
          </typeAliases>
          <!--可以写多套环境配置,s复数,可以编写多套配置环境,但是default只能选择一套 -->
          <environments default="Test">
              <!--这样就会选择Test的环境配置-->
              <environment id="Test">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <property name="driver" value="${driver}"/>
                      <property name="url" value="${url}"/>
                      <property name="username" value="${username}"/>
                      <property name="password" value="${password}"/>
                  </dataSource>
              </environment>
          </environments>
      
          <!--映射-->
          <mappers>
              <mapper class="com.haoyun.dao.blogMapper"/>
              <mapper resource="blogMapper.xml"/>
      
          </mappers>
      
      </configuration>
      
    4. 要注意setting标签编写的位置

    5. 设置 mapUnderscoreToCamelCase为true,名字不要打错

    6. https://mybatis.org/mybatis-3/zh/configuration.html#settings

    7. image-20200819212337706

  6. 编写工具类

    1. MybatisUtil这个工具类使用过好多次了,用来创建sqlsession

    2. public class MybatisUtil {
          private static SqlSessionFactory sqlSessionFactory = null;
      
          static {
              InputStream inputStream = null;
      
              try {
                  inputStream = Resources.getResourceAsStream("mybatis-config.xml");
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              }
              sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
          }
          public static SqlSession getSqlSession(){
              return sqlSessionFactory.openSession();
          }
      }
      
    3. 再写一个随机生成ID的,使用UUID方法

    4. public class IDutils {
          public static String getId(){
              return UUID.randomUUID().toString().replaceAll("-","");
          }
      }
      
    5. 将 “-” 替换为 “” 空

    6. 1a19b16580bb46588863d96fa4822d4f测试得到的id

  7. 环境整体结构

    1. image-20200819221313389

    2. 测试

    3. public class blogTest {
          @Test
          public void Test() {
              SqlSession sqlSession = MybatisUtil.getSqlSession();
              blogMapper mapper = sqlSession.getMapper(blogMapper.class);
              List<Blog> getblogs = mapper.getblogs();
              for (Blog getblog : getblogs) {
                  System.out.println(getblog);
              }
              sqlSession.close();
          }
      
          @Test
          public void TestInsert() {
              SqlSession sqlSession = MybatisUtil.getSqlSession();
              blogMapper mapper = sqlSession.getMapper(blogMapper.class);
      
              Blog blog = new Blog();
              blog.setId(IDutils.getId());
              blog.setTitle("TestTitle");
              blog.setAuthor("TestAuthor");
              //生成时间记得选择util包的Date
              blog.setCreateTime(new Date());
              blog.setViews(1200);
      
              mapper.addBook(blog);
              sqlSession.commit();
      
              sqlSession.close();
          }
      
          @Test
          public void IDutilsTest() {
              System.out.println(IDutils.getId());
          }
      
      }
      
    4. image-20200819221516689

动态SQL之IF语句

就是再Mapper.xml中添加if判断,实现sql的拼接,可以判断是否传递了对应列的参数来指定拼接对应的sql

流程:

  1. 添加接口方法

  2. 设置mapper.xml

    1. 加入if判断
  3. 测试

  4. 添加接口发方法

    1. List<Blog> queryBlogIF(Map map);
      
  5. 设置mapper.xml

    1.     <select id="queryBlogIF" parameterType="map" resultType="Blog">
              select * from blog
              <where>
                  <if test="title!= null">
                      and title = #{title}
                  </if>
                  <if test="author != null">
                      and author =#{author}
                  </if>
              </where>
          </select>
      
    2. 参数类型为map,返回值类型为Blog,这个添加了重命名

    3. 为了保证if条件都不符合,不进行拼接sql语句的情况,不能写成这样,这样拼接上是直接跟着and或or的,所以在if外要包上一层

    4. ​ select * from blog where

    5. 如果传递了参数,进行判断,然后拼接sql

  6. 测试

    1. @Test
      public void queryBlogIFTest(){
          SqlSession sqlSession = MybatisUtil.getSqlSession();
          blogMapper mapper = sqlSession.getMapper(blogMapper.class);
          HashMap hashMap = new HashMap();
          hashMap.put("title","sadfasdf");
          hashMap.put("author","l");
          List<Blog> blogs = mapper.queryBlogIF(hashMap);
          for (Blog blog : blogs) {
              System.out.println(blog);
          }
          sqlSession.close();
      
      }
      
    2. 结果

    3. image-20200820000023219

    4. 可以选择传入一个空的hashMap,查询的就是全表的信息

trim(where,set)

trim 切除

这个主要的功能就是,拼接字符串,然后删除语句后缀的逗号

<select id="updateBlog" parameterType="map" >
    update blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    where id = #{id}
</select>

根据编写内容不同选择不同的标签,这里是更新,所以加入了set标签,使用方法也是一样的,只是这里拼接到where的时候会取除末尾的标签中语句的逗号,当然,两个if都没用上,会直接报错的,因为set之后直接拼接where,造成语法错误

@Test
public void queryBlogIFTest(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    blogMapper mapper = sqlSession.getMapper(blogMapper.class);
    HashMap hashMap = new HashMap();
    hashMap.put("title","sadsdf");
    hashMap.put("author","test");
    hashMap.put("id","1");

    mapper.updateBlog(hashMap);
    sqlSession.commit();
    sqlSession.close();
}

image-20200820011834196

最后author末尾的逗号是被消除了

choose(when,otherwise )

choose 选择

when 什么情况下

otherwise 否则

规则有点像switch,只去匹配case中的一个值,唯一不同的就是otherwise必须添加参数,如果走了where就不会走otherwise,where都没走就会走otherwise,执行顺序是从上往下执行的,先判定上面的where

choose语句

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

多种情况测试

  1. 不填参数

  2. @Test
    public void queryBlogIFTest(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        blogMapper mapper = sqlSession.getMapper(blogMapper.class);
        HashMap hashMap = new HashMap();
        //hashMap.put("title","sadfasdf");
        //hashMap.put("author","l");
        //hashMap.put("views","55");
        List<Blog> blogs = mapper.queryBlogChoose(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }
    
  3. image-20200820003308068

  4. 自动的添加了views条件但是parameter为null

  5. 没查询出来

  6. hashMap.put("views",10);
    
  7. image-20200820003727498

  8. 所以前面的when没有参数就会添加otherwise中的语句

  9. 加入中间when值

  10. hashMap.put("author","l");
    hashMap.put("views",10);
    
  11. 加入了中间的author when判断和otherwise判断

  12. image-20200820004121140

  13. 但是只执行了when的语句,otherwise并没有执行

  14. when优先级

  15. hashMap.put("title","sadfasdf");
    hashMap.put("author","l");
    hashMap.put("views",10);
    
  16. 三条都加入了

  17. image-20200820004240099

  18. 但是只执行了第一条

  19. 所以第一条的优先级最高

总结:

  • 什么参数都不加的情况下会选择otherwise中的语句
  • 第一个多条when条件,从上往下判断,执行排在上面的
  • 只选择一条,包括otherwise

共同的父亲trim

image-20200820012342128

如果前置有set关键字,就会删除无关的逗号,prefix 前缀

image-20200820012513803

指定的是一个where,如果存在就会删除指定的内容

image-20200820012714201

这是定制化sql用的一些东西

SQL片段

有一些重复的语句,可以提取出代码片段,实现sql语句的复用

<sql id="if_title_author">
    <if test="title!= null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author =#{author}
    </if>
</sql>

<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <include refid="if_title_author"/>
    </where>
</select>

最好sql片段不要编写太复杂的事情,要不然重用效率就变低了

不要存在where标签,where是要根据条件语句来查询的加入就不好实现复用

foreach

<select id="queryBlogForEach" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id = ${id}
        </foreach>
    </where>
</select>

传入一个map类型参数,返回值是一个Blog类型

collection 传递进一个集合,集合的名称为ids,那么用map传递参数的时候就要对应ids名进行传参

里面的每个元素是id,传递了集合就会进行自动的遍历集合,传递参数进id中,

open开始,加入where是为了解决select * from where 1=1 后面必须跟指定条件成立的语句,要不然动态sql没有进入foreach就会变成 select * from where 导致语句错误,加入where标签,还能根据判断去除不必要的and或or

这里就是open开始,填装了一个and (,注意,and和( 之间是有一个空格的,要不然where会识别不出来

在日志中查看得出的结果就是这样

image-20200820082236707

本来用来连接其他条件的语句,不连接其他条件,and没有被去除,导致语句出错

close foreach结束时添加

separator 分隔符,用来分隔集合中元素的分隔符

最后给集合元素传参

@Test
public void queryBlogForEachTest(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    blogMapper mapper = sqlSession.getMapper(blogMapper.class);
    HashMap hashMap = new HashMap();
    ArrayList<String> arrayList = new ArrayList<String>();
    arrayList.add("1");
    arrayList.add("2");
    arrayList.add("3");
    hashMap.put("ids",arrayList);
    List<Blog> blogs = mapper.queryBlogForEach(hashMap);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.commit();
    sqlSession.close();
}

总结:

动态sql,本质还是sql,只是在sql层面,去执行一个逻辑代码,按照sql格式进行拼接,排列组合,去除不必要的字符

先在Mysql中写出完整的sql,再去修改实现动态sql,实现通用

多去看官方文档

怎么使用普通的sql查询还是不够的,需要多去了解更深层次的知识

  • mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值