十一、动态SQL
什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
搭建环境
创建一张表
CREATE TABLE `bolg` (
`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;
创建一个基础工程
-
导包
-
编写配置文件
-
编写实体类
@Data @NoArgsConstructor @AllArgsConstructor public class Blog { private String id; private String title; private String author; private Date createTime;//设置驼峰命名映射 private int views; }
-
编写实体类对应的Mapper接口和Mapper.xml文件
public interface BlogMapper { //插入数据 int addBlog(Blog blog); }
<insert id="addBlog" parameterType="blog"> insert into mybatis.bolg (id, title, author, create_time, views) values (#{id}, #{title}, #{author}, #{createTime}, #{views}); </insert>
IF
可以实现SQL语句的判断拼接
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.bolg
<where>
<if test="title != null">
and title=#{title}
</if>
<if test="author != null">
and author=#{author}
</if>
</where>
</select>
比如此时,如果不传递title和author,那么会查出全部的数据。
ps:使用where标签
choose(when, otherwise)
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="queryBlog" parameterType="map" resultType="blog">
SELECT * FROM mybatis.bolg
<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)
set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(译者注:因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)
<update id="updateBlog" parameterType="blog">
update mybatis.bolg
<set>
<if test="title != null">
title=#{title},
</if>
<if test="author">
author=#{author},
</if>
<if test="views != 0">
views=#{views},
</if>
</set>
where id=#{id}
</update>
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.bolg
<where>
<if test="title != null">
and title=#{title}
</if>
<if test="author != null">
and author=#{author}
</if>
</where>
</select>
若你对 set 元素等价的自定义 trim 元素的代码感兴趣,那这就是它的真面目:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
注意这里我们删去的是后缀值,同时添加了前缀值。
如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。
所谓动态SQL,本质上就是SQL语句,只不过可以在SQL层面上执行一些逻辑代码
SQL片段
有时候我们可能将一些功能的部分抽取出来,方便复用
<sql id="sql">
select * from mybatis.bolg;
</sql>
<select id="queryBlog" parameterType="map" resultType="blog">
<!--引用sql片段-->
<include refid="sql"></include>
</select>
- 使用SQL标签抽取公共的部分
- 在需要使用的地方使用include标签即可
注意事项
- 最好通过单表来定义SQL片段
- 不要存在where标签
forEach
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM Bolg b
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
实际使用:
<!--我们现在传递一个万能的Map,这个map中可以存在一个集合-->
<select id="queryBlogForEach" parameterType="map" resultType="blog">
select * from mybatis.bolg
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
动态SQL就是在拼接SQL语句,我们要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
建议:
- 先在mysql中写出完整版的SQL语句,再去修改成为动态SQL实现通用即可