前言:
小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个Mybatis基础学习系列是用来记录我学习Mybatis框架基础知识的全过程 (这个系列是参照B站狂神的Mybatis最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将尽量以两天一更的速度更新这个系列,还没有学习Mybatis3框架的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。最后,希望能够和大家一同进步吧!加油吧!少年们!
特别提醒:如果对Mybatis基础学习系列感兴趣,可以阅读本系列往期博客:
第一篇:Mybatis基础学习之初识Mybatis
第二篇:Mybatis基础学习之第一个Mybatis程序
第三篇:Mybatis基础学习之CRUD增删改查
第四篇:Mybatis基础学习之万能的Map和模糊查询
第五篇: Mybatis基础学习之配置解析(上篇)
第六篇: Mybatis基础学习之配置解析(下篇)
第七篇: Mybatis基础学习之使用ResultMap解决字段名不一致
第八篇: Mybatis基础学习之日志工厂的简单使用
第九篇: Mybatis基础学习之数据分页的简单使用
第十篇: Mybatis基础学习之使用注解开发
第十一篇: Mybatis基础学习之Lombok的简单使用
第十二篇: Mybatis基础学习之多对一关系处理
第十三篇: Mybatis基础学习之一对多关系处理
今天我们来到了Mybatis基础学习的第十三站:动态SQL的简单使用。废话不多说,让我们开始今天的学习内容吧。
13. 动态SQL的简单使用
13.1 动态SQL基础知识
13.1.1 什么是动态SQL?
动态SQL就是根据不同的条件生成不同的SQL语句
13.1.2 动态SQL好处
利用动态 SQL,可以彻底摆脱拼接时要确保忘记添加必要的空格和注意去掉列表最后一个列名的逗号等问题。
13.1.2 动态SQL官方解释
- 动态SQL元素和JSTL或任何基于类XML的文本处理器类似,在MyBatis之前的版本中,很多元素需要花时间了解
- MyBatis3大大精简了元素种类,现在只需要学习原来一半的元素即可
- MyBatis采用功能强大的基于OGNL的表达式来淘汰其它大部分元素
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
13.2 搭建环境和插入信息
13.2.1 编写SQL语句
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;
13.2.2 创建基础工程
1.导入资源依赖jar包
- 创建完Maven项目后,在pom.xml配置文件中导入相应的资源依赖
<dependencies>
<!-- mysql驱动资源依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- mybatis资源依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- junit单元测试资源依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log4j资源依赖 -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Lombok资源依赖 -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
<!-- 在build中配置resources,来防止我们资源导出失败的问题 -->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
2.编写核心配置文件
- 首先在resources文件目录下创建db.properties配置文件和mybatis-config.xml配置文件
2-1 编写db.properties配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
pwd=123456
2-2 编写mybatis-config.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- configuration: 核心配置 -->
<configuration>
<!-- 引入外部配置文件: 优先使用外部配置文件 -->
<properties resource="db.properties"/>
<!-- 设置标准日志输出 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 通过给包起别名 -->
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<!-- 设置默认环境为开发环境 -->
<environments default="development">
<!-- 设置一道环境为开发环境 -->
<environment id="development">
<!--transactionManager: 表示事务管理器, 而MyBatis的默认管理器是JDBC-->
<transactionManager type="JDBC"/>
<!-- dataSource: 数据源, 作用: 连接数据库(MyBatis的默认数据源类型是POOLED,也就是有池的连接) -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- 绑定接口:使用class文件绑定注册 -->
<mappers>
<!-- 同包同名,使用class文件就可以找到, 可以使用注解去测,跟接口配置文件互补-->
<mapper class="com.kuang.dao.BlogMapper"/>
</mappers>
</configuration>
3.编写Java实体类和Utils工具类
3-1 编写Blog实体类
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
// 使用@Data注解, 引入无参构造、get、set、toString等方法
@Data
// 使用@AllArgsConstructor注解, 引入有参构造方法
@AllArgsConstructor
// 使用@NoArgsConstructor注解, 引入无参构造方法
@NoArgsConstructor
public class Blog {
private String id; // 博客id
private String title; // 博客标题
private String author; // 作者
private Date createTime; // 创建时间
private int views; // 浏览量
}
3-2 编写MybatisUtils工具类
package com.kuang.utils;
/**
* SqlSessionFactoryBuilder: 建造工厂
* --> sqlSessionFactory: 生产sqlSession
* --> sqlSession
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
// 静态方法体
static {
try {
// 读取配置文件
String resource = "mybatis-config.xml";
// 解析配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 获取工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
*/
public static SqlSession getSqlSession() {
// 设置参数为true,实现自动提交
return sqlSessionFactory.openSession(true);
}
}
3-3 编写IdUtils工具类
package com.kuang.utils;
import org.junit.Test;
import java.util.UUID;
// 使用@SuppressWarnings注解, 抑制所有的警告
@SuppressWarnings("all")
public class IdUtils {
public static String getId() {
// 使用UUID,把"."替换为"-"
// return UUID.randomUUID().toString().replaceAll(".","-");
// 使用UUID,把"-"替换为""
return UUID.randomUUID().toString().replaceAll("-","");
}
// 测试IdUtils工具类
@Test
public void test() {
// 打印输出生成的三个不同的UUID
System.out.println(IdUtils.getId());
System.out.println(IdUtils.getId());
System.out.println(IdUtils.getId());
}
}
测试结果:
结果:成功生成的三个不同的UUID!
4.编写BlogMapper接口及其映射文件
4-1 编写BlogMapper接口
package com.kuang.dao;
import com.kuang.pojo.Blog;
public interface BlogMapper {
// 插入数据
int addBlog(Blog blog);
}
4-2 编写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="com.kuang.dao.BlogMapper">
<!-- 插入博客信息 -->
<insert id="addBlog" parameterType="blog">
insert into mybatis.blog(id, title, author, create_time, views)
values (#{id}, #{title}, #{author}, #{createTime}, #{views})
</insert>
</mapper>
5.编写测试类和测试结果
5-1 编写MyTest测试类代码
package com.kuang.dao;
import com.kuang.pojo.Blog;
import com.kuang.utils.IdUtils;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.Date;
public class MyTest {
@Test
public void addBlog() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化Blog实体类
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对象
sqlSession.close();
}
}
5-2 测试结果
- 查看控制台输出
- 查看数据库信息
结果:成功插入了四条数据!
13.3 使用IF语句实现查询
13.3.1 修改Mapper接口及映射文件
1. 修改BlogMapper接口
package com.kuang.dao;
import com.kuang.pojo.Blog;
public interface BlogMapper {
// 查询博客
List<Blog> queryBlogIF(Map map);
}
2. 修改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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息 -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
<!-- where 1=1 首先不会妨碍到正常的查询,其次方便了下面and条件的拼接 -->
Select * from mybatis.blog where 1=1
<!-- 判断标题是否为空 -->
<if test="title != null">
<!-- 若不为空,进行下列的and条件拼接 -->
and title = #{title}
</if>
<!-- 判断作者是否为空 -->
<if test="author !=null">
<!-- 若不为空,进行下列的and条件拼接 -->
and author = #{author}
</if>
</select>
</mapper>
13.3.5 编写测试类和测试结果
1. 编写MyTest测试类代码
package com.kuang.dao;
public class MyTest {
// 查询博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
//关闭sqlSession对象
sqlSession.close();
}
}
2. 测试结果
报错:
Caused by: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement ‘com.kuang.dao.BlogMapper.queryBlogIF’. It’s likely that neither a Result Type nor a Result Map was specified.
导致报错的原因是:
没有返回结果类型,即未在对应的Mapper接口映射文件中设置resultType
13.2.6 修改后重新测试
1.修改BlogMapper.xml映射文件
- 在select标签中加入resultType返回结果类型
<?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.kuang.dao.BlogMapper">
<!-- 查询博客信息(加上resultType结果返回类型)-->
<select id="queryBlogIF" parameterType="map" resultType="blog">
<!-- Select * from mybatis.blog where title = #{title} and author = # {author} -->
<!-- where 1=1 首先不会妨碍到正常的查询,其次方便了下面and条件的拼接 -->
Select * from mybatis.blog where 1=1
<!-- 判断标题是否为空 -->
<if test="title != null">
<!-- 若不为空,进行下列的and条件拼接 -->
and title = #{title}
</if>
<!-- 判断作者是否为空 -->
<if test="author !=null">
<!-- 若不为空,进行下列的and条件拼接 -->
and author = #{author}
</if>
</select>
</mapper>
2.测试结果
结果:成功查询到所有的博客信息!
13.2.7 查询指定条件博客信息
1.使用一个指定条件查询
1-1 修改MyTest测试类
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","Java如此简单");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
1-2 测试结果
结果:成功查询到标题为"Java如此简单"的博客文章!
2.使用多个指定条件查询
2-1 修改MyTest测试类
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
//设置标题信息
map.put("title","Java如此简单");
// 设置作者信息
map.put("author","狂神说");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
//关闭sqlSession对象
sqlSession.close();
}
}
1-2 测试结果
结果:成功查询到标题为"Java如此简单"并且作者为"狂神说"的博客文章!
13.4 使用where标签实现查询
13.4.1 常规方法测试
1.修改BlogMapper.xml文件
- 在13.3.4编写的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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息: 使用动态SQL中的IF -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
Select * from mybatis.blog where
<!-- 判断标题是否为空 -->
<if test="title != null">
<!-- 若不为空,进行下列的条件拼接 -->
title = #{title}
</if>
<!-- 判断作者是否为空 -->
<if test="author != null">
<!-- 若不为空,进行下列的and条件拼接 -->
and author = #{author}
</if>
</select>
</mapper>
2.修改MyTest测试类
2-1 设置标题和作者信息
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","Java如此简单");
// 设置作者信息
map.put("author","狂神说");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
//关闭sqlSession对象
sqlSession.close();
}
}
2-2 只设置标题信息
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","Java如此简单");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
2-3 只设置作者信息
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置作者信息
map.put("author","狂神说");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
3.测试结果
3-1 设置标题和作者信息
结果:成功查询到标题为“Java如此简单”,作者为“狂神说”的博客信息!
3-2 只设置标题信息
结果:成功查询到标题为“Java如此简单”的博客信息!
3-3 只设置作者信息
报错:
Caused by:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘and author = ‘狂神说’’
分析:
SQL语句的编写出错,where和author=?之间存在and!
13.4.2 使用where标签测试一
1.修改BlogMapper.xml文件
- 在13.3.4编写的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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息:使用where标签 -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
Select * from mybatis.blog
<where>
<!-- 判断标题是否为空 -->
<if test="title != null">
<!-- 若为条件一为空,条件二不为空,则去除此条件和后面的and
若条件一不为空,条件二为空,则去除and连同后面的条件二
若二者都为空,则去除where子句的所有条件 -->
title = #{title}
</if>
<!-- 判断作者是否为空 -->
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
</mapper>
2.修改MyTest测试类
2-1 只设置作者信息
- 与13.4.1中的只设置作者信息的代码相同
2-2 标题和作者信息同时设置
- 与13.4.1中的设置标题和作者信息的代码相同
3.测试结果
3-1 只设置作者信息
结果:成功查询到作者为“狂神说”的所有博客信息!
结论:
因此,我们发现,使用where标签后,如果只满足第二个条件(即标题信息为空,但作者信息不为空),它会自动去掉多余的and及前面的条件
3-2 标题和作者信息都设置
结果:成功查询到了标题为“Java如此简单”并且作者为“狂神说”的博客信息!
结论:
因此,我们发现,使用where标签后,如果两个条件都满足(即标题和作者都不为空),它又会自动加上之前多余的and连同前面的条件
13.4.3 使用where标签测试二
1.编写BlogMapper接口和配置文件
1-1 编写BlogMapper接口
package com.kuang.dao;
import com.kuang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
// 查询博客: 使用Choose
List<Blog> queryBlogChoose(Map map);
}
1-2 编写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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息: 使用where标签 -->
<select id="queryBlogChoose" parameterType="map" resultType="blog">
Select * from mybatis.blog
<where>
<!-- 若为条件一为空,条件二不为空,则去除此条件和后面的and
若条件一不为空,条件二为空,则去除and连同后面的条件二
若二者都为空,则去除where子句的所有条件 -->
<if test="title != null">
id = #{id}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
</mapper>
2.编写MyTest测试类
- 未设置标题和作者信息
package com.kuang.dao;
public class MyTest {
// 查询博客信息:使用where标签
@Test
public void queryBlogChoose() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
//实例化HashMap
HashMap map = new HashMap();
//调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogChoose(map);
//遍历List集合
for (Blog blog : blogs) {
System.out.println(blog);
}
//关闭sqlSession对象
sqlSession.close();
}
}
3.测试结果
结果:成功查询到了所有的博客信息!
结论:
因此,我们发现,使用where标签后,如果条件都不满足(即标题和作者都为空),它还会自动删除后面的where及连同的条件
13.4.4 where标签的使用总结
- where元素只会在至少有一个子元素的条件返回SQL子句(即至少满足一个条件)的情况,才会自动插入“where”子句
- 如果语句的开头为“and”或“or”,where元素也会将它们自动去除
13.5 使用choose语句实现查询
13.5.1 编写BlogMapper接口及其映射文件
1.编写BlogMapper接口
package com.kuang.dao;
import com.kuang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
// 查询博客:使用Choose
List<Blog> queryBlogChoose(Map map);
}
2.编写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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息: 使用Choose语句 -->
<select id="queryBlogChoose" parameterType="map" resultType="blog">
Select * from mybatis.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>
</mapper>
13.5.2 编写测试类
1.只设置播放量信息
package com.kuang.dao;
public class MyTest {
// 查询博客信息:使用choose语句实现
@Test
public void queryBlogChoose() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置浏览量信息
map.put("views","9999");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogChoose(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blog);
}
//关闭sqlSession对象
sqlSession.close();
}
}
2.设置标题和播放量信息
package com.kuang.dao;
public class MyTest {
// 查询博客信息:使用choose语句实现
@Test
public void queryBlogChoose() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","Spring如此简单");
// 设置浏览量信息
map.put("views","9999");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogChoose(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blog);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
13.5.3 测试结果
1.只设置播放量信息
结果:成功查询到播放量为9999的所有博客信息!
2.设置标题和播放量信息
结果:成功查询到标题为“Spring如此简单”的博客信息!
分析:
但其播放量为10000,与所设置的播放量9999不一致,但却成功能查询出来
13.5.4 测试总结
由此看来,choose(when,othersize)相当于Java中的switch…case…语句,当标题满足一个条件(即标题为“Spring如此简单”)时,因为又使用了where标签,便自动去除and后面的条件,然后便结束查询
13.6 使用set标签实现更新
1365.1 编写BlogMapper接口及其配置文件
1.编写BlogMapper接口
package com.kuang.dao;
import com.kuang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
// 更新博客
int updateBlog(Map map);
}
2.编写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="com.kuang.dao.BlogMapper">
<!-- 更新博客信息:使用set标签 -->
<update id="updateBlog" 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>
</mapper>
13.5.2 编写测试类
1.设置标题,作者和id信息
package com.kuang.dao;
public class MyTest {
// 更新博客信息:使用set标签
@Test
public void updateBlog() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","JavaWeb如此简单");
// 设置作者信息
map.put("author","遇见狂神说");
// 设置id信息
map.put("id","999542fc1e1344908ef4cd22fe664906");
// 调用updateBlog方法,实现更新博客信息
mapper.updateBlog(map);
// 关闭sqlSession对象
sqlSession.close();
}
}
2.只设置id信息
package com.kuang.dao;
public class MyTest {
// 更新博客信息:使用set标签
@Test
public void updateBlog() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","JavaWeb如此简单");
// 设置id信息
map.put("id","999542fc1e1344908ef4cd22fe664906");
// 调用updateBlog方法,实现更新博客信息
mapper.updateBlog(map);
// 关闭sqlSession对象
sqlSession.close();
}
}
3.设置标题和id信息
package com.kuang.dao;
public class MyTest {
// 更新博客信息:使用set标签
@Test
public void updateBlog() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置id信息
map.put("id","999542fc1e1344908ef4cd22fe664906");
// 调用updateBlog方法,实现更新博客信息
mapper.updateBlog(map);
// 关闭sqlSession对象
sqlSession.close();
}
}
13.5.3 测试结果
1.设置标题,作者和id信息
- 查看控制台输出
- 查看数据库信息
结果:成功修改id为“999542fc1e1344908ef4cd22fe664906”的博客信息!
2.只设置id信息
结果:更新博客信息失败!
报错:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘where id = ‘999542fc1e1344908ef4cd22fe664906’’
分析:
由于where子句条件前的set语句缺失,导致更新失败
3.设置标题和id信息
- 查看控制台输出
- 查看数据库信息
结果:仍然成功修改了id为“999542fc1e1344908ef4cd22fe664906”的博客信息!
13.5.4 测试结论
虽然未设置作者信息,但是使用了set标签后,自动去除标题条件后面的逗号以及作者信息条件
13.7 使用trim(where,set)语句
13.7.1 使用trim(where)语句
<trim prefix="where" prefixOverrides="and | or">
...
</trim>
refix=“where”:是否加上前缀where
prefixOverrides=“and | or”: 是否替换and或者or,如果不存在前缀where,则替换"and | or"
"and | or"在语句的前面
13.7.2 使用trim(set)语句
<trim prefix="set" suffixOverrides=",">
...
</trim>
prefix=“set”:是否加上前缀set
suffixOverrides=",":是否替换掉”,“,如果不存在前缀set,则替换","
","在语句的后面
13.7.3 使用总结
- prefix表示设置前缀,值通常可设为“where”或者“set”
- prefixOverrides表示句前覆盖,若前缀不存在,自动去除其设置值,通常可设置为“and | or”
- suffixOverrides表示句后覆盖,若后缀不存在,自动去除其设置值,通常可设置为“,”
因此,所谓动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
常用的标签:if,where,set,choose,when
13.8 使用SQL片段
有的时候,我们可能会将一些功能的部分抽取出来,方便复用!
13.8.1 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标签引用
- 在需要使用的地方使用include标签引用即可
<!-- 查询博客信息:使用where标签 -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
Select * from mybatis.blog
<where>
<!-- refid: 引用的id,这里指之前写好的的sql标签的id -->
<include refid="if-title-author"></include>
</where>
</select>
13.8.2 SQL片段使用测试
1.修改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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息: 使用sql和include标签 -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
Select * from mybatis.blog
<where>
<!-- 使用include标签引用
refid:引用的id,这里指之前写好的的sql标签的id -->
<include refid="if-title-author"></include>
</where>
</select>
<!-- 使用sql标签抽取公共部分 -->
<sql id="if-title-author" >
<!-- 判断标题是否为空 -->
<if test="title != null">
title = #{title}
</if>
<!-- 判断作者是否为空 -->
<if test="author != null">
and author = #{author}
</if>
</sql>
</mapper>
2.修改MyTest测试类
2-1 只设置标题信息
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置标题信息
map.put("title","Java如此简单");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
2-2 只设置作者信息
package com.kuang.dao;
public class MyTest {
// 查询指定的博客信息
@Test
public void queryBlogIF() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取Mapper1接口对象
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 设置作者信息
map.put("author","狂神说");
// 调用queryBlogIF方法,将map放入,获取List集合
List<Blog> blogs = mapper.queryBlogIF(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blogs);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
3.测试结果
3-1 只设置标题信息
结果:成功查询到标题为“Java如此简单”的博客信息!
3-2 只设置作者信息
结果:成功查询到作者为“狂神说”的所有博客信息!
13.8.3 使用SQL片段的注意事项
- 最好基于单表来定义SQL片段
- 不要存在where标签
13.9 使用ForEach语句
动态SQL中可以使用foreach语句对集合进行遍历,通常是在构建in条件语句的时候
13.9.1 编写BlogMapper接口
package com.kuang.dao;
import com.kuang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
// 更新博客
List<Blog> queryBlogForeach(Map map);
}
13.9.2 修改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="com.kuang.dao.BlogMapper">
<!-- 查询博客信息:使用foreach标签 -->
<!-- 现在传递一个万能的map,这个map中可以存在一个集合-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
Select * from mybatis.blog
<where>
<!-- foreach: 遍历集合; item: 集合项; index: 索引(一般不使用);
collection: 集合; open: 开头; close: 结尾; separator: 分隔符 -->
<foreach item="id" collection="ids" open="and (" separator="or" close=")">
id = #{id}
</foreach>
</where>
</select>
</mapper>
13.9.3 修改MyTest测试类
1. 只把ids集合放入到map中
package com.kuang.dao;
public class MyTest {
// 查询博客信息: 使用foreach标签
@Test
public void queryBlogForeach() {
// 获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取BlogMapper接口
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 实例化ArrayList(存入ids这个集合)
ArrayList<Integer> ids = new ArrayList<Integer>();
// 把ids放入到map中
map.put("ids",ids);
// 获取Blog的List集合列表
List<Blog> blogs = mapper.queryBlogForeach(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blog);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
2. 添加集合项并且把ids集合放入到map中
package com.kuang.dao;
public class MyTest {
// 查询博客信息: 使用foreach标签
@Test
public void queryBlogForeach() {
// 获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取BlogMapper接口
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
// 实例化HashMap
HashMap map = new HashMap();
// 实例化ArrayList(存入ids这个集合)
ArrayList<Integer> ids = new ArrayList<Integer>();
// 添加id为1的集合项
ids.add(1);
// 添加id为2的集合项
ids.add(2);
// 把ids放入到map中
map.put("ids",ids);
// 获取Blog的List集合列表
List<Blog> blogs = mapper.queryBlogForeach(map);
// 遍历List集合
for (Blog blog : blogs) {
System.out.println(blog);
}
// 关闭sqlSession对象
sqlSession.close();
}
}
13.9.4 测试结果
1. 只把ids集合放入到map中
结果:成功查询到所有的博客信息!
2.添加集合项并且把ids集合放入到map中
结果:成功查询到id为1和2的博客信息!
13.9.5 动态SQL测试总结
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
建议:先在MySQL中写出完整的SQL,再去对应的修改成为动态SQL,实现通用即可
好了,今天的有关 动态SQL的简单使用 的学习就到此结束啦。欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连。我们下期见,拜拜啦!