动态SQL
1. 概念
动态SQL:动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
总结:根据不同的条件生成不同的sql语句
动态sql主要有以下四个标签:
-
if
-
choose (when, otherwise)
-
trim (where, set)
-
foreach
在mapper.xml文件中使用这四个标签灵活调度sql语句。
2. 环境搭建
以blog为例,进行动态sql的学习
-
创建blog数据库表
create table blog( `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 public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
在这一步有两个问题:
-
createTime这个属性 与数据库表create_time字段不对应,解决方案是在xml配置文件中setting标签有一个属性为mapUnderscoreToCamelCase(是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。) 设置为true就能实现java属性驼峰命名到数据库下划线命名映射。
-
我们要实现id为自动生成随机的内容,解决方案是写一个工具类
public class IDUtils { public static String getId(){ return UUID.randomUUID().toString().replaceAll("-",""); } }
随机生成一个UID,并把其中的“-” 替换为空
-
-
向数据库表blog中插入数据
3. IF标签
在select标签中进行条件的判断,根据判断结果向原来的sql语句中追加不同的sql语句
场景:我们在查询blog时,传入的参数为title 和 author ,当这两个参数为空时我们希望所有的blog都被查出来,当参数不为空时,只查该有该参数的结果。
实现:
-
mapper.xml
<select id="queryBlogIF" resultType="Blog" parameterType="map"> select * from blog where 1=1 <if test="title != null"> and title = #{title} </if> <if test="anthor != null"> and author = #{author} </if> </select>
if标签中的 test 属性就是判断条件,如果满足就拼接标签里面的内容
-
首先不往map中放值,也就是title和author都为null
@Test public void test02(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); mapper.queryBlogIF(map) sqlSession.close(); }
四条结果都显示出来了
-
往map中放入title和author的值
只有一条对应参数的记录
4. trim(where,set)
where
官方对于where标签的解释:where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
对于上面的案例来说,我们在sql语句中是这样写的
select * from blog where 1=1
显然 where 1=1 是不合乎规定的,我们可以使用where标签来控制where子句的存在与否
<select id="queryBlogIF" 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>
如果两个if判断都不满足,那么就没有where子句,sql就变成了 select * from blog
如果只传入title,sql变成了:select * from blog where title = #{title}
如果只传入author,sql变成了 select * from blog where author = #{author} ,它会自动将and去除
如果都传入,sql就为:select * from blog where title = #{title} and author = #{author}
set
官方解释:
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
<update id="updateBlogSet" 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标签会自动为sql添加set关键字,并且可以去掉多余的逗号
trim
官方:
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
举例:
trim标签有四个属性
prefix:前缀 ,可以自定义前缀
prefixOverrides:前缀覆盖,可以覆盖掉sql语句中的prefixOverrides 包含的内容
<select id="queryBlogIF" resultType="Blog" parameterType="map">
select * from blog
<trim prefix="where" prefixOverrides="and">
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</trim>
</select>
我们自定义的前缀为where,并且可以覆盖掉sql前面的and
suffix:后缀,也可以自定义
suffixOverrides:后缀覆盖,可以覆盖掉sql后面的内容
<trim prefix="where" prefixOverrides="and" suffixOverrides=",">
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author},
</if>
</trim>
注意看,我们在第二个if标签中的sql后面多加了个逗号,如果没有suffixOverrides="," 就会报错,加上它,它就会帮你覆盖掉最后的逗号。
5. choose (when, otherwise)
官方对于choose的解释:有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
是的choose标签就像java的switch语句,只满足其中一条就结束判断
choose标签中,包含的是when和otherwise标签
when标签就相当于case , otherwise相当于default
<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>
views = #{views}
</otherwise>
</choose>
</where>
</select>
如果title不为空,那么sql就是 select * from blog where title = #{title}
title为空,author不为空 sql就是:select * from blog where author = #{author}
title和author都为空,sql'就是:select * from blog where views = #{views}
如果什么都不传,sql是:select * from blog WHERE views = ? 也就什么也查不出来
6.sql片段
当动态sql中存在一些重复的代码,我们可以将他们提取出来,作为sql片段,用以复用。
举个例子:像上面的案例
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author},
</if>
这段代码频繁地出现在每个动态sql中,我们可以将它们提取为sql片段
sql片段是通过 sql 标签来实现的
<sql id="if-title-author" >
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIF" resultType="Blog" parameterType="map">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
在sql标签中,属性就是这个给这个sql片段取的标识符,在sql片段里面,放复用的代码
在使用这个sql片段的地方,用include标签来引用,属性refid就是sql片段的 id
注意:
-
最好基于单表进行sql片段的定义
-
不要在sql片段里写where标签
7.foreach
foreach是对集合进行遍历
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
foreach的属性有:
collecton:指定一个集合,遍历这个集合中的内容
item:集合中的每一项
index:集合中每一项的索引
open:要拼接的sql语句的前缀
close:要拼接的sql语句的后缀
separator:集合的每一项中间的分隔符
使用场景案例:
我们要找数据库中某三个元素
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="titles" item="title" open="(" separator="or" close=")">
title = #{title}
</foreach>
</where>
</select>
public void test05(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<String> titles = new ArrayList<>();
titles.add("mybatis动态sql");
titles.add("mybatis注解开发");
titles.add("mybatis配置优化");
map.put("titles",titles);
mapper.queryBlogForeach(map);
sqlSession.close();
}
最后的sql语句为:select * from blog WHERE ( title = ? or title = ? or title = ? )
8.总结
所谓的动态sql本质还是sql,只是我们在sql层面去执行一些逻辑代码,根据不同的条件生成不同的sql语句
动态sql就是在拼接sql语句
标签:title,author,笔记,SQL,blog,sql,动态,where,select From: https://www.cnblogs.com/wztblogs/p/17037008.html