一、MyBatis中的动态SQL
什么是动态SQL:动态SQL就是根据不同的参数及条件生成不同的SQL语句
MyBatis中动态SQL元素
- if
- choose(when,otherwise)
- trim(where,set)
- foreach
- sql片段
1、创建基本环境
-
创建数据库表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
-
创建实体类Blog
对应表blog的字段,创建Blog类
package org.westos.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @AllArgsConstructor @NoArgsConstructor public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
-
创建对应的接口BlogMapper
package org.westos.mapper; import org.westos.pojo.Blog; import java.util.Map; public interface BlogMapper { //添加博客 public void addBlog(Blog blog); }
-
创建对应的xml配置文件BlogMapper.xml
<?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="org.westos.mapper.BlogMapper"> <insert id="addBlog" parameterType="org.westos.pojo.Blog"> INSERT INTO `blog`(`id`,`title`,`author`,`create_time`,`views`) VALUES (#{id},#{title},#{author},#{createTime},#{views}) </insert> </mapper>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zWr0PEkL-1582304351170)(assets/1582271343949.png)]
-
开启下划线转驼峰命名
因为数据库表中字段命名一般使用下划线隔开单词,而Java变量使用驼峰命名,所以在多单词命名时,数据库字段名就会和Java属性名不一致,这个时候只需要在MyBatis核心配置文档mybatis-config.xml中,配置一下就可以自动进行转换了
<settings> <!--开启下划线转驼峰命名--> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
-
开启日志
开启事务能够在控制台打印程序执行的详细信息,帮助我们改错
在下划线转驼峰命名的配置下方进行配置
<settings> <!--开启下划线转驼峰命名--> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--开启日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
-
使用unit测试工具进行测试
往表中添加博客记录,以便后面进行观察
package org.westos.mapper; import org.junit.Test; import org.westos.pojo.Blog; import org.westos.utils.IDUtils; import org.westos.utils.MyBatisUtil; import java.util.Date; public class BlogMapperTest { @Test public void testAddBlog() { //传递参数,默认开启事务提交 BlogMapper mapper = MyBatisUtil.getSession(true).getMapper(BlogMapper.class); Blog blog; //循环给表中添加数据 for (int i = 0; i < 10; i++) { blog = new Blog(); blog.setId(IDUtils.getId()); blog.setTitle("文章" + i); blog.setAuthor("北风"); blog.setCreateTime(new Date()); blog.setViews(i * 1000); mapper.addBlog(blog); } } }
-
IDUtils工具类
工具类,创建随机数,作为文章的id
package org.westos.utils; import java.util.UUID; public class IDUtils { public static String getId() { return UUID.randomUUID().toString().replaceAll("-", ""); } }
2、if标签
常用于where语句、update语句、insert语句中,通过判断if后表达式的取值决定是否使用if标签中的子句。
当判断条件为真的时候,添加if标签中的子句,当判断条件为假的时候,什么都不加
if是与的关系(and)
java代码
//BlogMapper接口新增方法
//查询博客
List<Blog> getBlogByIf(Map map);
//BlogMapperTest中新增测试方法
@Test
public void testGetBlogByIf() {
BlogMapper mapper = MyBatisUtil.getSession(true).getMapper(BlogMapper.class);
//创建Map集合,用的参数从Map集合中拿
Map<String, String> map = new HashMap<String, String>();
map.put("title","wenzhang1");
map.put("author","beifeng");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
xml配置
<!--根据if标签后的表达式的值来决定SQL语句-->
<select id="getBlogByIf" parameterType="Map" resultType="Blog">
select * from mybatis.blog where
<!--通过判断if后表达式的值,决定是否要添加if标签中的子句-->
<if test="title!=null">
title=#{title}
</if>
<if test="author!=null">
and author =#{author}
</if>
</select>
3、choose标签(when,otherwise)
类似于Java中的switch语句,当匹配到成立的when标签后的条件时,就执行这个when标签后的SQL子句,choose标签结束。当所有的when标签都不成立时,执行otherwise标签中的SQL子句
choose是或的关系(or)
java代码
//BlogMapper新增接口
List<Blog> queryBlogByChoose(Map map);
//测试类新增测试方法
@Test
public void testQueryBlogByChoose() {
BlogMapper mapper = MyBatisUtil.getSession().getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title", "wenzhang1");
map.put("author", "beifeng");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
xml配置
<!--使用choose标签-->
<select id="queryBlogByChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<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>
4、trim标签(where,set)
where:当where标签中有返回值的话,它就插入一个where子句,如果没有,如果标签返回的内容是以 AND 或 OR 或 “,” 开头结尾的,则它会删除掉
java代码
//接口
List<Blog> selectBlogByWhere(Map map);
//测试方法
@Test
public void testSelectBlogByWhere() {
BlogMapper mapper = MyBatisUtil.getSession().getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title", "wenzhang1");
map.put("author", "beifeng");
List<Blog> blogByIf = mapper.selectBlogByWhere(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
xml配置
<select id="selectBlogByWhere" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
set:当在 update 语句中使用 if 标签时,如果最后的 if 没有执行,则或导致逗号多余错误。使用 set 标签可以将动态的配置 set关键字,并删除追加到条件末尾的任何不相关的逗号
java代码
//接口
int updateBlogBySete(Map map);
//测试方法
@Test
public void testUpdateBlogBySete() {
//开启事务提交
BlogMapper mapper = MyBatisUtil.getSession(true).getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//给Map中填充数据
map.put("title", "123123123");
map.put("author", "11111111");
map.put("id", "8bc79ab97f6f4887a2e61ae7d6512453");
//打印受影响行数
int i = mapper.updateBlogBySete(map);
System.out.println(i);
}
xml配置
<update id="updateBlogBySete" parameterType="map">
update mybatis.blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
5、foreach标签
foreach主要用于构建in条件,也可在SQl中对集合进行迭代。批量增删等操作
foreach标签的属性
-
collection
表明存储的参数类型,对应的值分别为:list(List)、array(数组)、map(map集合)
-
item
在迭代的过程中元素的别名
-
index
在迭代的过程中,迭代的位置
-
open
前括号
-
close
后括号
-
separator
分隔符,表示迭代的时候以什么符号分隔元素
java代码
//接口
List<Blog> getBlogByForeach(Map map);
//测试方法
@Test
public void testGetBlogByForeach() {
BlogMapper mapper = MyBatisUtil.getSession().getMapper(BlogMapper.class);
Map<String, List> map = new HashMap<String, List>();
List<String> ids = new ArrayList<String>();
ids.add("8bc79ab97f6f4887a2e61ae7d6512453");
ids.add("d38e8e24768249eb8c0a671e64e5991f");
ids.add("35e3643a0ab14b18b018b72146d1f0d4");
map.put("ids", ids);
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
xml配置
<select id="getBlogByForeach" parameterType="map" resultType="blog">
select * from user where
<!--得到map集合里的键值对,值为List集合,然后遍历得到值,使用or链接起来-->
<foreach item="id" collection="ids"
open="(" separator="or" close=")">
#{id}
</foreach>
</select>
6、SQL片段
将一些SQL语句公用的部分抽取出来,实现代码复
-
使用SQL标签抽取公共的部分
<sql id="if-title-author"> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql>
-
将前面的if标签引用进来,使用include标签
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <include refid="if-title-author"></include> </where> </select>