什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句
? 我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。
? 那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 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;
创建一个基础maven工程
编写实体类
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private Integer views;
// 空参、满参构造
// getter setter
// toString
}
添加一个IdUtil工具类生成UUID
public class IdUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
}
编写实体类对应mapper和mapper.xml文件
public interface BlogMapper {
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jh.mapper.BlogMapper">
</mapper>
配置mybatis核心配置文件
<settings>
<!-- 设置下划线驼峰自动转换 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启log4j日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<mappers>
<!-- 注册mapper文件 -->
<mapper class="com.jh.mapper.BlogMapper"/>
</mappers>
插入初始化数据
public interface BlogMapper {
int addBlog(Blog blog);
}
<insert id="addBlog">
insert into mybatis.blog(id, title, author, create_time, views)
values (#{id}, #{title}, #{author}, #{createTime}, #{views});
</insert>
@Test
public void addBlog() {
SqlSession session = MyBatisUtils.getSqlSession(true);
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IdUtils.getId());
blog.setTitle("Mybatis如此简单");
blog.setAuthor("秦老师");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlog(blog);
blog.setId(IdUtils.getId());
blog.setTitle("Java如此简单");
mapper.addBlog(blog);
blog.setId(IdUtils.getId());
blog.setTitle("Spring如此简单");
mapper.addBlog(blog);
blog.setId(IdUtils.getId());
blog.setTitle("微服务如此简单");
mapper.addBlog(blog);
session.close();
}
需求:根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
编写接口类
public interface BlogMapper {
List<Blog> queryBlogIf(Map<String, Object> map);
}
编写SQL
<select id="queryBlogIf" resultType="com.jh.domain.Blog">
select * from mybatis.blog where
<if test="title != null and title != ‘‘">
and title = #{title}
</if>
<if test="author != null and author != ‘‘">
and author = #{author}
</if>
</select>
测试
@Test
public void queryBlogIf() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("title", "Mybatis如此简单");
map.put("author", "秦老师");
List<Blog> blogList = mapper.queryBlogIf(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}
这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句!
修改上面的SQL语句;
<select id="queryBlogIf" resultType="com.jh.domain.Blog">
select *
from mybatis.blog
<where>
<if test="title != null and title != ‘‘">
title = #{title}
</if>
<if test="author != null and author != ‘‘">
and author = #{author}
</if>
</where>
</select>
? 这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行update更新操作的时候,含有 set 关键词,我们怎么处理呢?
编写接口方法
public interface BlogMapper {
int updateBlog(Blog blog);
}
编写sql文件
<update id="updateBlog">
update mybatis.blog
<!--
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
(这些逗号是在使用条件语句给列赋值时引入的)
-->
<set>
<if test="title != null and title != ‘‘">
title=#{title},
</if>
<if test="author != null and author != ‘‘">
author = #{author}
</if>
</set>
where id = #{id};
</update>
测试
@Test
public void updateBlog() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId("9d6a763f5e1347cebda43e2a32687a77");
blog.setTitle("动态SQL");
blog.setAuthor("秦疆老师");
int result = mapper.updateBlog(blog);
System.out.println(result);
sqlSession.close();
}
trim 元素来定制 where或者set 元素的功能。
<trim prefix="" suffix="" prefixOverrides="" suffixOverrides=""></trim>
和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND|OR ">
...
</trim>
与 set 元素等价的自定义 trim 元素为:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
? 有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
编写接口
public interface BlogMapper {
List<Blog> queryBlogIf(Map<String, Object> map);
}
编写sql
<select id="queryBlogIf" resultType="com.jh.domain.Blog">
select *
from mybatis.blog
<where>
<!--
when里的条件成立时,执行里面的语句
如果when都不成立,则执行otherwise里的语句
when从上往下执行,有一个条件成立,下面的语句就不会执行
-->
<choose>
<when test="title != null and title != ‘‘">
title = #{title}
</when>
<when test="author != null and author != ‘‘">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
测试
@Test
public void queryBlogIf() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("title", "Mybatis如此简单");
map.put("author", "秦老师");
map.put("views", 9999);
List<Blog> blogList = mapper.queryBlogIf(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}
所谓的动态SQL,本质就是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
? 有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
抽取SQL片段:
<sql id="if-title-author">
<if test="title != null and title != ‘‘">
title = #{title}
</if>
<if test="author != null and author != ‘‘">
and author = #{author}
</if>
</sql>
引用SQL片段:
<select id="queryBlogIf" resultType="com.jh.domain.Blog">
select *
from mybatis.blog
<where>
<!-- 使用include标签引用sql标签,refid的值为sql标签的id属性 -->
<include refid="if-title-author"/>
</where>
</select>
注意:
? foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
先将数据库中前三个数据的id修改为1,2,3;
需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息
具体实现:
编写mapper接口
List<Blog> queryBlogForeach(Map<String, Object> map);
编写SQL
<!-- select * from mybatis.blog where id in(1,2,3) -->
<select id="queryBlogForeach" resultType="com.jh.domain.Blog">
select *
from mybatis.blog
<where>
<foreach collection="ids" item="id" open="id in(" separator="," close=")">
#{id}
</foreach>
</where>
</select>
测试
@Test
public void queryBlogForeach() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids", ids);
List<Blog> blogList = mapper.queryBlogForeach(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}
小结:动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了。为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它的技巧。
动态SQL在开发中大量的使用,一定要熟练掌握!
推荐大家去了解:
原文:https://www.cnblogs.com/paidaxing0623/p/14276417.html