动态SQL详解 
什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句 
1 2 3 4 5 如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。 if choose (when, otherwise) trim (where, set) foreach 
所谓的动态SQL本质上还是SQL语句,只是我们可以在SQL层面上,去执行逻辑代码。 
一、环境搭建 
1. 创建blog表 
1 2 3 4 5 6 7 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 
2. 新建Blog实体类 
1 2 3 4 5 6 7 8 9 @Data @NoArgsConstructor public  class  Blog      private  int  id;     private  String title;     private  String author;     private  Date create_time;     private  int  views; } 
3. 新建BlogMapper接口 
1 2 3 4 package  com.nichu.dao;public  interface  BlogMapper  } 
4. 编写Blog.xml 
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper          PUBLIC  "-//mybatis.org//DTD Config 3.0//EN"          "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper  namespace ="com.nichu.dao.BlogMapper" > </mapper > 
5. 在核心配置文件中绑定接口 
1 2 3 4 <mappers >     <mapper  class ="com.nichu.dao.BlogMapper" />  </mappers > 
6. 编写IDutils工具类用于生成UUID 
1 2 3 4 5 6 7 import  java.util.UUID;public  class  IDutils      public  static  String getId ()          return  UUID.randomUUID().toString().replaceAll("-" ,"" );     } } 
7. 开启驼峰命名自动转换 
在核心配置文件中配置 
1 2 3 4 5 6 7 <settings >               <setting  name ="logImpl"  value ="STDOUT_LOGGING" />           <setting  name ="mapUnderscoreToCamelCase "  value ="true" />  </settings > 
编写测试类并插入数据 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public  void  addBlogTest ()     SqlSession sqlSession = MybatisUtils.getSqlSession();     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);     Blog blog = new  Blog();     blog.setId(IDutils.getId());     blog.setTitle("Mybatis" );     blog.setAuthor("狂神说" );     blog.setCreateTime(new  Date());     blog.setViews(9999 );     mapper.addBook(blog);     blog.setId(IDutils.getId());     blog.setTitle("Java" );     mapper.addBook(blog);     blog.setId(IDutils.getId());     blog.setTitle("Spring" );     mapper.addBook(blog);     blog.setId(IDutils.getId());     blog.setTitle("微服务" );     mapper.addBook(blog);     sqlSession.close(); } 
二、if 
1 2 3 4 5 6 7 8 9 10 11 <select  id ="queryBlogIF"  parameterType ="Map"  resultType ="com.nichu.pojo.Blog" >     select * from mybatis.blog where 1=1          <if  test ="title!=null" >          and title = #{title}     </if >           <if  test ="author!=null" >          and author = #{author}     </if >  </select > 
1 2 3 4 5 6 7 8 9 10 11 12 public  void  addBlogTest ()      SqlSession sqlSession = MybatisUtils.getSqlSession();     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);     Map map = new  HashMap();          map.put("author" ,"狂神说" );     List<Blog> blogs = mapper.queryBlogIF(map);     for  (Blog blog : blogs) {         System.out.println(blog);     }     sqlSession.close(); } 
三、 choose (when, otherwise) 
用法相当于java中的switch (case default) 
chose --> switch
执行时只要满足其中一个条件就结束 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select  id ="queryBlogChoose"  parameterType ="Map"  resultType ="com.nichu.pojo.Blog" >     select * from mybatis.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 > 
四、 trim (where, set) 
因此只要将查询语句中的where部分用 <where > 标签包裹即可
 
<set>标签的意义和<where>标签一样,每设置一个属性,都要在语句后加 “,” 由于不知道哪个语句结尾,所有要用<set>标签自动处理。
1 2 3 4 5 6 7 8 9 10 11 12 <update  id ="updateBlog"  parameterType ="map" >     update mybatis.blog     <set >          <if  test ="title!=null" >              title = #{title},         </if >          <if  test ="author!=null" >              author = #{author},         </if >      </set >      where id = #{id} </update > 
<trim>可以自定义<where>标签和<set>标签 
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。 
 
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
1 2 3 <trim  prefix ="WHERE"  prefixOverrides ="AND |OR " >   ... </trim > 
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。 
 
以下是set 元素等价的自定义trim
1 2 3 <trim  prefix ="SET"  suffixOverrides ="," >   ... </trim > 
五、SQL片段 
有时候,我们可能会将一些功能的部分抽取出来,方便复用!
使用SQL标签抽取公共的部分 
 
1 2 3 4 5 6 7 8 <sql  id ="if-title-author" >     <if  test ="title!=null" >          and title = #{title}     </if >      <if  test ="author!=null" >          and author = #{author}     </if >  </sql > 
在需要使用的地方使用Include标签引用即可 
 
1 2 3 4 5 6 7 <select  id ="queryBlogIF"  parameterType ="Map"  resultType ="com.nichu.pojo.Blog" >     select * from mybatis.blog     <where >                   <include  refid ="if-title-author" > </include >      </where >  </select > 
注意事项 
最好基于单表来定义SQL片段! 
不要存在where标签 
 
六、<foreach>标签 
1. 查询id为(1-2-3)的博客记录 
SQL语句:
1 2 select  *  from  mybatis.blog where  id in  (1 ,2 ,3 )select  *  from  mybatis.blog where  (id= 1  or  id= 2  or  id= 3 )
2. 使用foreach遍历id 
1 2 3 4 5 6 7 8 <select  id ="queryBlogForEach"  parameterType ="map"  resultType ="com.nichu.pojo.Blog" >     select * from mybatis.blog         <where >              <foreach  collection ="ids"  open ="and ("  close =")"  separator ="or"  item ="id" >                  id=#{id}             </foreach >          </where >  </select > 
3. 编写测试类 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public  void  addBlogTest ()      SqlSession sqlSession = MybatisUtils.getSqlSession();     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);     Map map = new  HashMap();          ArrayList<Integer> ids = new  ArrayList<>();     ids.add(1 );     ids.add(2 );     ids.add(4 );     map.put("ids" ,ids);     List<Blog> blogs = mapper.queryBlogForEach(map);     for  (Blog blog : blogs) {         System.out.println(blog);     }     sqlSession.close(); } 
关于动态SQL的一些建议 
先在MySQL中写出完整的SQL语句,再对应的去修改成为动态SQL实现通用即可。