动态SQL
目录
什么是动态SQL: 根据不同的条件生成不同的SQL语句
1. 搭建环境
1. 准备数据库
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;
2. 创建一个基础工程
-
导包
-
编写配置文件
-
编写实体类
package com.wang.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @NoArgsConstructor @AllArgsConstructor public class Blog { private int id; private String title; private String author; //日期用util包中的 private Date createTime; private int views; }
-
编写实体类对应Mapper接口和对应的xml文件
-
插入数据
-
创建一个工具类,利用UUID作为数据库的id
package com.wang.utils; import java.util.UUID; public class IdUtils { public static String getId() { return UUID.randomUUID().toString().replaceAll("-", ""); } }
-
编写插入数据的接口及对应的mapper
package com.wang.dao; import com.wang.pojo.Blog; public interface BlogMapper { //插入数据 int addBlog(Blog blog); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wang.dao.BlogMapper"> <insert id="addBlog" parameterType="Blog"> insert into blog(id, title, author, create_time, views) values (#{id}, #{title}, #{author}, #{createTime}, #{views}); </insert> </mapper>
-
插入数据
package com.wang.dao; import com.wang.pojo.Blog; import com.wang.utils.IdUtils; import com.wang.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.Date; public class MyTest { @Test public void TestAddBlog() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.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); //增删改查要开启事务 sqlSession.commit(); sqlSession.close(); } }
-
2. IF
1. 编写接口
//查询博客
List<Blog> queryBlogIF(Map map);
2. 编写mapper文件
<select id="queryBlogIF" parameterType="map" resultType="Blog">
select * from blog where 1 = 1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
3. 测试
@Test
public void TestQueryBlogIF() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("author", "狂神说");
List<Blog> blogs = mapper.queryBlogIF(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
3. choose(when, otherwise)
类似Java中的switch语句, 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">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
4. tirm(where, set)
1. where
由于使用where语句,如果第一个if不使用,则会在where后直接跟and,从而导致SQL语句报错
在之前的if标签中,使用了where 1 = 1来避免这种情况,但是这样写时不正规的
因此我们下面使用where标签来解决此问题
<select id="queryBlogIF" 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 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。**
2. set
使用set标签解决update只更新部分字段导致出现无关的逗号导致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>
3. trim
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能
1. 与where等价的trim
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
2. 与set等价的trim
<trim prefix="SET" suffixOverrides=",">
...
</trim>
5. Foreach
<!--我们现在传递一个万能的map, 这个map中可以存在一个集合
foreach中的collection标签为遍历的集合,item为集合中的元素
open为每一个遍历元素的对应语句的头开头,close为结尾
separator为其分隔符
-->
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
@Test
public void TestQueryBlogForeach() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> ids = new ArrayList<>();
for (int i = 1; i < 4; i++) {
ids.add(i);
}
map.put("ids", ids);
List<Blog> blogs = mapper.queryBlogForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
6. SQL片段
有的时候,我们会将一些公共的部分抽取出来,方便复用
1. 使用sql标签抽取公共的部分
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
2. 在需要使用的地方使用include标签引用即可
<select id="queryBlogIF" parameterType="map" resultType="Blog">
select * from blog
<where>
<include refid="if-title-author">
</include>
</where>
</select>
3. 注意事项
- 最好基于单表来定义SQL片段
- 不要存在where标签
7. 动态SQL的本质
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
8. 总结
- 动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
- 建议:
- 先在MySQL中写出完整的SQL语句
- 再对应的去修改成为我们的动态SQL实现通用即可