一 动态SQL
什么是动态sql?
动态SQL就是说根据不同的条件,生成不同的sql语句!!!!
二 if标签
<if test="title!=null" >
title=#{title}
</if>
这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)。
对比:
1 原先的Blog.xml文件当中的语句
<select id="queryBlogByTitleAndAuthor" resultType="Blog" parameterType="map"> select * from blog where title=#{title}and author=#{author}
可能会出现的状况:
1.1 设置参数不完整
@Test //原来的通过title和author查询blog 如果测试的时候参数不设置或者错误就会报错 public void testqueryBlogByTitleAndAuthor(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第一本书"); //map.put("author","莫言"); List<Blog> blogs = mapper.queryBlogByTitleAndAuthor(map); for (Blog blogs2 : blogs) { System.out.println(blogs2); } sqlSession.close(); }
1.2参数设置的与上去了语句不匹配 参数设置title和view字段而sql语句是title和author字段
@Test //原来的通过title和author查询blog 如果测试的时候参数不设置或者错误就会报错 public void testqueryBlogByTitleAndAuthor(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第一本书"); map.put("view",9999); List<Blog> blogs = mapper.queryBlogByTitleAndAuthor(map); for (Blog blogs2 : blogs) { System.out.println(blogs2); } sqlSession.close(); }
都会显示没有查询结果
1.3只有与sql语句的条件完成匹配才可以搜索出来
@Test //原来的通过title和author查询blog 如果测试的时候参数不设置或者错误就会报错 public void testqueryBlogByTitleAndAuthor(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第一本书"); map.put("author","莫言"); List<Blog> blogs = mapper.queryBlogByTitleAndAuthor(map); for (Blog blogs2 : blogs) { System.out.println(blogs2); } sqlSession.close(); }
2 利用动态sql后(利用动态sql就不会)
BlogMapper.xml文件代码:
<select id="queryBlogByIF" resultType="Blog" parameterType="map" > select * from blog where <if test="title!=null" > title=#{title} </if> <if test="author!=null"> and author=#{author} </if>
2.1设置完整
@Test //通过动态sql当中if标签实现 如果测试的时候参数不设置就全部显示 public void testqueryBlogByIF(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第二本书"); map.put("author","莫言"); List<Blog> blogs = mapper.queryBlogByIF(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
2.2.测试的时候设置参数不完整也可以按照第一个的查询
这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title}
@Test //通过动态sql当中if标签实现 如果测试的时候参数不设置就全部显示 public void testqueryBlogByIF(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第二本书"); //map.put("author","莫言"); List<Blog> blogs = mapper.queryBlogByIF(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
2.3如果设置第二个条件也会报错 因为sql语句错误了 需要使用trim当中的<where>标签
这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句!
@Test //通过动态sql当中if标签实现 如果测试的时候参数不设置就全部显示 public void testqueryBlogByIF(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","莫言第二本书"); map.put("author","莫言"); List<Blog> blogs = mapper.queryBlogByIF(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
上图当中SQL语句错误了。
使用了<where>标签
代码:
<select id="queryBlogByIF" resultType="Blog" parameterType="map" > select * from blog <where> <if test="title!=null" > title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </where> </select>
这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉
2.4 测试的时候设置的参数类型与sql语句不一样 sql当中是title和author字段而测试时是author和views字段
@Test //通过动态sql当中if标签实现 如果测试的时候参数不设置就全部显示 public void testqueryBlogByIF(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","莫言第二本书"); map.put("author","莫言"); map.put("view",9999); List<Blog> blogs = mapper.queryBlogByIF(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
2.5 如果测试的时候设置的参数都不是sql的呢? 全部显示
@Test //通过动态sql当中if标签实现 如果测试的时候参数不设置就全部显示 public void testqueryBlogByIF(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","莫言第二本书"); //map.put("author","莫言"); map.put("view",9999); List<Blog> blogs = mapper.queryBlogByIF(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
那就是全部显示了
2.7如果什么都不设置呢?全部显示
@Test //通过动态sql当中if标签实现 如果测试的时候参数不设置就全部显示 public void testqueryBlogByIF(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","莫言第二本书"); //map.put("author","莫言"); //map.put("view",9999); List<Blog> blogs = mapper.queryBlogByIF(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
三 choose标签
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句
BlogMapper.xml文件代码:
<select id="queryBlogByChoose" parameterType="map" resultType="Blog"> select * from blog <where> <choose> <when test="title!=null"> title=#{title} </when> <when test="views==9999"> and views=#{views} </when> <otherwise> and author=#{author} </otherwise> </choose> </where> </select>
1 按照第一个case:设置title
a 测试类单独设置了title的
@Test public void testqueryBlogByChoose(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第一本书"); List<Blog> blogs = mapper.queryBlogByChoose(map); for (Blog blogs4 : blogs) { System.out.println(blogs4); } sqlSession.close(); }
b 测试类还设置了别的参数
@Test public void testqueryBlogByChoose(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第一本书"); map.put("views",1000); //map.put("author","史铁生"); List<Blog> blogs = mapper.queryBlogByChoose(map); for (Blog blogs4 : blogs) { System.out.println(blogs4); } sqlSession.close(); }
2 按照第二个 views=9999
@Test public void testqueryBlogByChoose(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("views",9999); List<Blog> blogs = mapper.queryBlogByChoose(map); for (Blog blogs4 : blogs) { System.out.println(blogs4); } sqlSession.close(); }
在views=9999的基础上额外加上author=“史铁生”
@Test public void testqueryBlogByChoose(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","莫言第一本书"); map.put("views",9999); map.put("author","史铁生"); List<Blog> blogs = mapper.queryBlogByChoose(map); for (Blog blogs4 : blogs) { System.out.println(blogs4); } sqlSession.close(); }
3 前面条件都不满足
@Test public void testqueryBlogByChoose(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","莫言第一本书"); map.put("views",1000); map.put("author","史铁生"); List<Blog> blogs = mapper.queryBlogByChoose(map); for (Blog blogs4 : blogs) { System.out.println(blogs4); } sqlSession.close(); }
四 trim标签
4.1where标签
where标签如上诉所示 在if标签当中的例子
4.2 set标签
同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?
<update id="updateBlogBySet" parameterType="map" > update blog <set> <if test="title!=null"> title=#{title}, </if> <if test="author!=null"> author=#{author} </if> </set> where id=#{id} </update>
注意逗号
1 修改作者和标题 通过id 测试的时候相应的参数全部输入
@Test //通过动态SQL当中的set标签 会像where一样 set智能的省略 ”,“ 和前置set标签 public void testUpdateBySet(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","settitle为动态sql的莫言第一本书"); map.put("author","setauthor为动态sql的莫言2号"); map.put("id","1"); mapper.updateBlogBySet(map); System.out.println(); sqlSession.close(); }
注意sql语句
注意事物的提交 否则数据库单中不会修改
2注释第一个条件
@Test //通过动态SQL当中的set标签 会像where一样 set智能的省略 ”,“ 和前置set标签 public void testUpdateBySet(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //map.put("title","settitle为动态sql的莫言第一本书"); map.put("author","setauthor为动态sql的莫言2号"); map.put("id","1"); mapper.updateBlogBySet(map); sqlSession.commit(); sqlSession.close(); }
3 注释第二个条件 我们可以看到 条件一后面的,被智能的省略了 只是由于set标签的作用
@Test //通过动态SQL当中的set标签 会像where一样 set智能的省略 ”,“ 和前置set标签 public void testUpdateBySet(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","settitle为动态sql的莫言第一本书"); //map.put("author","setauthor为动态sql的莫言2号"); map.put("id","1"); mapper.updateBlogBySet(map); sqlSession.commit(); sqlSession.close(); }
五 foreach标签
遍历
需求:我想要查询id为1-3的记录 不采用分页 可以使用foreach标签
BlogMapper.xml文件
代码:
<!-- collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 separator:遍历对象之间需要拼接的字符串 select * from blog where 1=1 and (id=1 or id=2 or id=3) --> <select id="queryBlogByForEach" parameterType="map" resultType="Blog"> select * from blog <where> <foreach collection="ids" open="(" separator="or" close=")" item="id"> id=#{id} </foreach> </where> </select>
测试类代码
@Test public void testqueryBlogByForEach(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); ArrayList ids = new ArrayList(); ids.add("1"); ids.add("2"); ids.add("3"); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogByForEach(map); for (Blog blogs6 : blogs) { System.out.println(blogs6); } sqlSession.close(); }
6 sql片段
sql片段 利用sql标签
需求:
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
BlogMapper.xml文件的代码
提取sql片段
<sql id="if-title-author" > <if test="title!=null" > title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </sql>
引用sql片段
<select id="queryBlogByIF2" parameterType="map" resultType="Blog" > select * from blog <where> <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace --> <include refid="if-title-author" > <!-- 在这里还可以引用其他的 sql 片段 --> </include> </where> </select>
测试类代码
@Test //优化 使用sql片段 减少代码的重用性 public void testqueryBlogByIF2(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","莫言第二本书"); map.put("author","莫言"); //map.put("view",9999); List<Blog> blogs = mapper.queryBlogByIF2(map); for (Blog blogs3 : blogs) { System.out.println(blogs3); } sqlSession.close(); }
注意:
①、最好基于 单表来定义 sql 片段,提高片段的可重用性
②、在 sql 片段中不要包括 where
小结:其实动态 sql 语句的编写往往就是一个拼接的问题,
为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。
多在实践中使用才是熟练掌握它的技巧。
强调一下动态SQL 功能点
1 if标签
不同的参数实现动态效果 在sql当中判断
比如说我想查询书名是《狂神这么厉害》 那我就需要一个方法是通过书名 再给个参数来查询记录
我想查询作者是“狂神说” 那么我又需要一个方法就是:通过作者 再给个作者的参数 来查询记录
就会有很多个方法 代码的累赘
=====》》》如果使用了动态sql
就需要这么多个方法 只需要一个方法 且利用sql语句的动态性 改变参数就可以实现上述效果。
2 chooes标签
他其实就好比Java当中的switch语句 并且他不会像原始的方法那样必须参数对参数全部都要一样才可以 利用动态sql可以动态的改变 根据不同的条件得到不同的结果集。
3foreach标签
遍历 比如说我想要某几条数据 需要给出索引下标就可以得到 不需要用分页的
4 trim标签
trim标签包含<where>和<set>这两个子标签
where的作用是前置where和智能的省略and和or关键字
set的作用是前置set关键字和智能的省略逗号”,“
动态SQL的关键就是
根据不同的条件得到不同的结果集。
动态sql的本身其实还是sql语句,只是我们在sql的层面上,去执行了一个逻辑代码!
动态SQL是拼接sql语句 我们需要保证他sql语句的正确性 。=======》》》》 因此我们需要先提前写好sql语句是否能够正常运行再去再mybatis当中的动态sql当中去修改