MyBatis之动态SQL的使用
Posted Mq_sir
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis之动态SQL的使用相关的知识,希望对你有一定的参考价值。
MyBatis之动态SQL的使用
什么是动态SQL:简单来说就是根据不同的的条件生成不同的sql语句
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
主要有
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
数据库准备,创建一个blok的表
create table blog(
id int primary key comment '博客id',
title varchar(100) not null comment '博客标题',
author varchar(30) not null comment '博客作者',
create_time varchar(50) not null comment '创建时间',
views int(30) not null comment '浏览量'
)
insert into blog values(1,'javaWeb教程','黑马程序员',now(),1000)
insert into blog values(2,'安卓软件开发','周世凯,陈小龙',now(),1000)
insert into blog values(3,'数据结构','清华大学出版社',now(),10000)
insert into blog values(4,'人文基础与应用','毛灿月',now(),560)
insert into blog values(5,'java教程','小钱',now(),123456)
insert into blog values(6,'C语言','谭浩强',now(),10000)
insert into blog values(7,'C语言','小毛',now(),10000)
编写实体类
@Data
public class Blog {
private int id;
private String title;
private String author;
private String create_Time;
private int views;
}
1、if语句
编写接口
// 通过if,查询博客
List<Blog> queryBlogIF(Map map);
编写Mapper.xml的sql语句
<select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">
select * from blog
<where>
<if test="title!=null">
and title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</where>
</select>
如果不传入 “title”,那么所有的 Blog 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行查找并返回对应的 Blog结果
where标签会在下面介绍
测试类
@Test
public void queryBlogIF(){
SqlSession sqlSession = Mybatisutil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","C语言");
map.put("author","谭浩强");
List<Blog> blogs = mapper.queryBlogIF(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
结果
2、choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
编写接口
// 通过choose,查询博客
List<Blog> queryBlogChoose(Map map);
编写Mapper.xml的sql语句
<select id="queryBlogChoose" parameterType="map" resultType="pojo.Blog">
select * from blog
<where>
<choose>
<when test="title!=null">
title=#{title}
</when>
<when test="author!=null">
and author=#{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
测试类
//通过choose查询
@Test
public void queryBlogChoose(){
SqlSession sqlSession = Mybatisutil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","C语言");
map.put("author","谭浩强");
List<Blog> blogs = mapper.queryBlogChoose(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
结果
当title满足要求时,即’break‘退出choose选择,就不会执行下面sql语句的拼接,和switch一样,所以这里查出来的有两条记录,当我只传入views参数时候,就会拼接 otherwise标签的语句,结果如下
3、trim、where、set
在我们拼接语句的时候,会有标点符号,前缀后缀符号等问题,这个时候可以用trim来解决。
如下面的sql语句,假如没有使用where标签,那么如果if语句中没有满足条件的拼接语句,这个时候我们的sql语句就是select * from blog where,这样的sql语句就是错误的,那么where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">
select * from blog
where
<if test="title!=null">
and title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</select>
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
来看看与 set 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
3.1、set修改数据
编写接口
//使用set修改数据
int updateBlog(Map map);
编写Mapper.xml的sql语句
<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>
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
测试类
@Test
public void updateBlog(){
SqlSession sqlSession = Mybatisutil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
//map.put("title","C语言");
map.put("author","小浩强");
map.put("id",6);
mapper.updateBlog(map);
sqlSession.close();
}
结果
4、Foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历
编写接口
//使用foreach查询3 4 5 条博客
List<Blog> queryBlogForeach(Map map);
编写Mapper.xml的sql语句
<select id="queryBlogForeach" parameterType="map" resultType="pojo.Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
测试类
@Test
public void queryBlogForeach(){
SqlSession sqlSession = Mybatisutil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> idlist = new ArrayList<>();
idlist.add(3);
idlist.add(4);
idlist.add(5);
map.put("idlist",idlist);
List<Blog> blogs = mapper.queryBlogForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
结果:
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
5、SQL片段
我们会将公共的部分提取出来,方便复用
使用:
- 使用SQL标签提取公共的部分
<!-- 将公共部分,需要重复使用的sql提取出来,使用sql标签-->
<sql id="if-titlt-author">
<if test="title!=null">
title=#{title},
</if>
<if test="author!=null">
and author=#{author}
</if>
</sql>
- 在需要使用的地方使用include标签
<!-- 在需要使用的地方使用include标签-->
<select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">
select * from blog
<where>
<include refid="if-titlt-author"></include>
</where>
</select>
注意事项:
- 最好基于单表来定义SQL片段
- 不要存在where标签
总结:
- 动态SQl就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列就行
- 书写sql语句之前先在sql查询环境中测试一下,避免写错,在编写Mappre.xml的时候找BUG。
以上是关于MyBatis之动态SQL的使用的主要内容,如果未能解决你的问题,请参考以下文章