4. trim(where,set)
4.1 where
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </where> </select>
- where元素只会在至少有一个子元素的条件返回SQL子句的情况下采取插入“WHERE”自子句,而且,若语句的开头为“AND“或”OR“,where元素也会将它们去除。
- 我们很容易看到,之前提到的if是用了一个where 1=1.其实这个是不合适的。但是现在加了个标签,它可以自动识别是不是第一个where,然后在判断是否加上and。
- where的存在会判断and是不是需要,第二个前面及以后要加上and。
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
4.2 set
- set元素会动态前置SET关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的SQL语句的后面留下这些逗号
<!--基本类型不需要resultType--> <update 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} </update>
@Test public void updateBlog(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("id","ac040b29e3b047a09a4fe78797193597"); map.put("author","王木木"); map.put("title","Java1"); mapper.updateBlog(map); sqlSession.close(); }
来看看与 set 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=","> ... </trim>
注意,我们覆盖了后缀值设置,并且自定义了前缀值。
5. choose(when,otherwise)
<select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from blog <where> <choose> <when test="title != null"> title = #{title} </when> <when test="author != null"> author = #{author} </when> <otherwise> and views = #{views} </otherwise> </choose> </where> </select>
select * from user where 1=1 and <foreach item="id" collection="ids" open="(" separator="or" close=")"> </foreach> (id=1 or id=2 or id=3)
这个choose有点像switch,case。他只能运行一个。比如说前面的都不符合,那他必须有一个views要符合,否则会报错。前面的按照顺序有一个符合了,那他就跳出去了。
6. foreach
select * from user where 1=1 and <foreach item="id" collection="ids" open="(" separator="or" close=")"> </foreach> (id=1 or id=2 or id=3)
使用
//查询第1-2-3号记录的博客 List<Blog> queryBlogForeach(Map map);
<!--传递一个万能的map,这个map可以存在一个集合--> <select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <where> <foreach item="id" collection="ids" open="and (" separator="or" close=")"> id = #{id} </foreach> </where> </select>
@Test public void queryBlogForeach(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); //这里因为是uuid是String,如果是1,2这种就用Integer ArrayList<String> ids = new ArrayList<String>(); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
我们还可以进行下面的测试
@Test public void queryBlogForeach(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); ArrayList<String> ids = new ArrayList<String>(); ids.add("ac040b29e3b047a09a4fe78797193597"); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
@Test public void queryBlogForeach(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); ArrayList<String> ids = new ArrayList<String>(); ids.add("ac040b29e3b047a09a4fe78797193597"); ids.add("a46a7874d69f4d69b9572816d8f30ab7"); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
7. SQL片段
有时候我们会将一些功能的部分抽取出来,方便复用
1. 使用SQL标签抽取公共的部分。
2.在需要使用的地方使用include标签引用即可
我们可以加一个sql标签,id可以随意取,然后下面来一个include refid是引用id,和上面的id是一个。这样就可以实现复用。
<sql id="if-title-author"> <if test="title != null"> 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>
3.注意事项:
- 最好基于单表来定义SQL片段
- 不要存在where标签
8. 总结
所谓的动态SQL,本质还是SQL语句,只是我们可以在sql层面,去执行一个逻辑代码。
if,where,set,choose,when
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就ok了
建议:
- 先在Mysql中写出完整的SQL,再对应的去修改成为我们的动态SQL。实现通用。