mybatis动态sql


1.动态SQL

  • 【官方声明】

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

    使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

    如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

1.1 IF关键字

1.1.1 动态SQL测试

  1. dao层 接口 => 【BlogsMapper】

    import java.util.List;
    import java.util.Map;
    
    public interface BlogsMapper {
    	// 创建【插入测试数据】的方法
        int addBlog(Blogs blog);
    
        // 创建【实现动态SQL查询】的方法
        List getBlogsByDynamicSQL(Map map);
    }
    
  2. XML映射文件 => 【BlogsMapper.xml】

    
    
  3. 测试实现类 => 【DaoTest】

    @Test
    public void getBlogsByDynamicSQL(){
        
        MyBatisUtils mybatis = new MyBatisUtils();
        SqlSession sqlSession = mybatis.getSqlSession();
        BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class);
        
        List blogs = mapper.getBlogsByDynaticSQL();
        for (Blogs blog : blogs){
            System.out.print(blog);
        }
        
        sqlSession.close();
    }
    

1.2 where、set,Foreach

foreach用法

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

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


  • IF【官方实例】

    • 失败案例

      • 前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 “state = ‘ACTIVE’” 设置成动态条件,看看会发生什么。

        
        
      • 如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:

        SELECT * FROM BLOG
        WHERE
        
      • 这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

        SELECT * FROM BLOG
        WHERE
        AND title like ‘someTitle’
        
    • 成功案例

      • 这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:

        
        
  • 【官方声明】

    • 标签:

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

      • 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

        //此案例实际上就是where这个标签的工作原理,在拼接sql前方/开头添加where,并去掉拼接语句整体最前方的and/or 单词
        
          
        
        
    • 标签:

      • 用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。

        
          update Author
            
              username=#{username},
              password=#{password},
              email=#{email},
              bio=#{bio}
            
          where id=#{id}
        
        

1.2.1 测试

  1. Dao层接口添加实现方法 => 【BlogsMapper】

    int updateBlogInfoBySet(Map map);
    
  2. XML映射文件 => 【BlogsMapper.xml】

    
        update test.blog 
        
        	 title = #{title}
             author = #{author}
             create_time = #{createTime}
             views = #{views>
        
    
    
  3. 测试实现类 => 【DaoTest】

    @Test
    public void dynamicSqlUpdateBySet(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class);
    
        HashMap map = new HashMap();
        map.put("title","updatedTitle");
        map.put("author","updatedAuthor");
        map.put("createTime", String.valueOf(new Date()));
        map.put("views","1");
        map.put("id","5bde3e48b521443bb40524988456a668");
    
        int i = mapper.updateBlogInfoBySet(map);
        if (i > 0 ){
            System.out.println("Update Succeed!");
        }
        sqlSession.close();
    }
    

14.3 choose、when、otherwise

  • 【官方声明】:有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

    • 例子

      
      

1.3.1 测试

1.3.1.1 环境搭建

  1. dao层接口添加方法 => 【BlogsMapper】

    List queryBlogsByChoose(Map map);
    
  2. xml映射文件 => 【BlogsMapper.xml】

    //choose标签类似于Java中的switch
    
         select * from mybatis.blog
         
     
    
  3. 测试实现类 => 【DaoTest】 (按测试情况进行配置 )

14.3.1.2 测试结果

  • 单个条件成立

    • 测试实现类 => 【DaoTest】

      @Test
      public void dynamicSqlChoose(){
          MyBatisUtils myBatisUtils = new MyBatisUtils();
          SqlSession sqlSession = myBatisUtils.getSqlSession();
          BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class);
      
          HashMap map = new HashMap();
          //创建单条件成立的集合
          map.put("title","MyBatis");
          System.out.println(mapper.queryBlogsByChoose(map));
      
          sqlSession.close();
      }
      
  • 多个条件成立

    • 测试实现类 => 【DaoTest】

      @Test
          public void dynamicSqlChoose(){
              MyBatisUtils myBatisUtils = new MyBatisUtils();
              SqlSession sqlSession = myBatisUtils.getSqlSession();
              BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class);
      
              HashMap map = new HashMap();
              //创建多个条件满足的集合
              map.put("title","MyBatis");
            	map.put("author","Camelot");
              System.out.println(mapper.queryBlogsByChoose(map));
      
              sqlSession.close();
          }
      
  • 都为false,为true

    • 测试实现类 => 【DaoTest】

      @Test
      public void dynamicSqlChoose(){
          MyBatisUtils myBatisUtils = new MyBatisUtils();
          SqlSession sqlSession = myBatisUtils.getSqlSession();
          BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class);
      
          //创建空集合传入
          HashMap map = new HashMap();
          System.out.println(mapper.queryBlogsByChoose(map));
      
          sqlSession.close();
      }
      
  • 结论

    标签会在多个条件都满足的情况下,仅会返回第一个传参的返回值。

    但当其他条件都不满足时,可以添加标签,用于返回一个固有值。

14.4 Trim

  • Trim可以自定义SQL语句中的规范,当标签、标签不满足时,可以使用Trim自定义。

14.4.1 Trim自定义测试

  • 使用Trim复写规则

14.4.1.1 实现

  1. Dao层接口 => 【BlogsMapper】

    List queryBlogsByTrim(Map map)
    
  2. XML映射器 => 【BlogsMapper.xml】

    
    
  3. 测试实现类 => 【DaoTest】

    @Test
    public void dynamicSqlSelectByTrim(){
        MyBatisUtils mybatis = new MyBatisUtils;
        SqlSession sqlSession = mybatis.getSqlSession();
        BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class);
    
        HashMap map = new HashMap();
        map.put("titleMap","MyBatis");
        map.put("authorMap","Altria");
    
        for (Blogs blog : mapper.queryBlogsByTrim(map)) {
            System.out.println(blog);
        }
    	
        sqlSession.close();
    }
    

1.4.1.2 实现

  1. Dao层接口 => 【BlogsMapper】

    int updateBlogInfoByTrim(Map map)
    
  2. XML映射文件 => 【BlogsMapper.xml】

    
    	update test.blog
        //suffix去后缀
             title = #{titleMap},
             author = #{authorMap},
        
        where id = #{idMap}
    
    
  3. 测试实现类 => 【DaoTest】

    @Test
    public void dynamicSqlUpdateByTrim(){
        
        MyBatisUtils mybatis = new MyBatisUtils();
        SqlSession sqlSession = mybatis.getSqlSession();
        BlogsMapper mapper = mybatis.getMapper(BlogsMapper.class);
        
        Map map = new HashMap();
        map.put("authorMap","Altria");
        map.put("titleMap","Spring Framework Updated");
        map.put("idMap","5aa45402bc764755b3ae406be6b27d33");
        
        int i = mapper.updateBlogInfoByTrim(map);
        if( i > 0 ){
            System.out.println("Update Succeed!");
        }
    }