前言
动态sql需要知道mapper.xml映射的各种标签
Mybatis - Mapper.xml映射器解析
mybatis动态sql是对sql语句的简化
什么是动态Sql
我们前面写的select * from student;
这种叫静态的sql
即sql已经写死了,不能改变了
而动态sql就是可以变化的sql语句,根据不同的条件生成不同的SQL语句
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{tid};
</select>
官方介绍
-
现实问题:根据不同条件拼接 SQL 语句很麻烦
-
解决:Mybatis封装了各种标签,省去了我们自己考虑各种需要注意的地方
有四种标签: if、choose (when, otherwise)、trim (where, set)、foreach
if
if标签和我们正常写java的if一样,表示选择:如果
<select id="selectBlog" parameterType="map" resultType="Blog">
select * from blog
where
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
如果title不为空,根据title 查询blog
测试类:
@Test
public void select(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","数据库从删库到跑路");
//map.put("author","李四");
List<Blog> blogs = mapper.selectBlog(map);
for (Blog blog : blogs){
System.out.println(blog);
}
}
先通过title查询
看日志输出:
author判断为空,就删去了后续的sql
如果选择输入author
//map.put("title","数据库从删库到跑路");
map.put("author","李四");
会报一个错误
因为我们在<if test="author != null"> and author = #{author} </if>
加了个and,当只有后面这个语句成立
sql就变成了select * from blog where and author = #{author}
,多了个and,但是and又是必不可少的
怎么解决?通过where标签
trim标签
<select id="selectBlog" 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变成标签,运行上面的错误语句
它自动帮我们把and去掉了
这就是官方说的
利用动态 SQL解决根据不同条件拼接 SQL 语句的痛苦
set标签和where标签的用法一样,只是set用在update上
如果没有set标签,第一个if成立,第二个不成立,那么第一个会多出一个逗号,又会报错
trim自定义
trim可以自定义的设置标签前缀、后缀、省略内容
前面的set标签可以改trim
<update id="updateBlog" parameterType="map" >
update blog
<trim prefix="set" suffixOverrides=",">
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</trim>
where id = #{id}
</update>
一样成功了:
这个标签,设置前缀prefix为set,即在该标签加上前缀set,suffix表示后缀
suffixOverrides表示覆盖后缀,prefixOverrides表示覆盖后缀
前面的where标签也可以修改:
覆盖后缀为and
<select id="selectBlog" parameterType="map" resultType="Blog">
select * from blog
<trim prefix="where" prefixOverrides="and">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</trim>
</select>
trim用于自定义sql需要的规则:前缀、后缀
choose、when、otherwise
类似与Java中的switch语句,在choose标签内,当when标签成立,运行when标签内是sql,如果when标签都不成立,运行otherwise标签的sql
<select id="selectBlogChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
author = #{author}
</when>
<otherwise>
views = 888;
</otherwise>
</choose>
</where>
</select>
当title不等于null,选择title = #{title}
,当author不等于null,选择author = #{author}
都不成立,运行<otherwise> views = 888; </otherwise>
这里可以省略and,因为choose标签内只能选择一个(和switch一样)
foreach
foreach在Java中是一种遍历方式,这个标签的作用也是一样的
<!--foreach 遍历查询
传递的map中存在一个集合,放入collection
select * from blog where 1=1 and (id = 1 or id = 2 or id = 3)
-->
<select id="selectBlogForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
测试语句:
传递一个集合给selectBlogForeach方法
@Test
public void selectBlogForeach(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
map.put("ids",ids);
List<Blog> blogs = mapper.selectBlogForeach(map);
for (Blog blog : blogs){
System.out.println(blog);
}
sqlSession.close();
}
结果:
类似与Java中的foreach循环
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
-
collection表示传入的集合名(使用map传递list键值对),List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键
-
item表示集合中元素迭代的别名,也就是#{id}这个id
-
open表示foreach开始符
-
close表示foreach结束符
-
separator表示元素间的分隔符
-
index:在list和数组中,index是元素的序号,在map中,index是元素的key
总结
动态sql标签是为了简便sql拼接的标签,一切为了偷懒、简便
学海无涯苦作舟
都看到这了,点个赞呗(^_−)☆