Java道经第3卷 - 第1阶 - MyBatis(一)
传送门:JB3-1-MyBatis(一)
传送门:JB3-1-MyBatis(二)
心法:本章使用 Maven 父子结构项目进行练习
练习项目结构如下:
|_ v3-1-ssm-mybatis
|_ test
武技:搭建练习项目结构
- 创建父项目 v3-1-ssm-mybatis,删除 src 目录。
- 在父项目中添加依赖:
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.13.2</junit.version>
<lombok.version>1.18.24</lombok.version>
<hutool.version>5.8.25</hutool.version>
<mysql-connector-j.version>8.2.0</mysql-connector-j.version>
<mybatis.version>3.5.13</mybatis.version>
</properties>
<dependencies>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!--hutool-all-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
- 在子项目 test 中添加依赖:
<!--mysql-connector-j-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-connector-j.version}</version>
<scope>runtime</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
S01. MyBatis基础入门
心法:MyBatis 是一个底层半封装了 JDBC 的持久层的开源 ORM 框架,,其前身是 Apache 的 iBatis 项目,2010 年迁移到了 GoogleCode 并改名为 MyBatis,2013 年 11 月迁移到 Github。
半封装框架:MyBatis 封装了驱动,连接,Statement 等业务代码,但不封装 SQL 语句。
MyBatis 核心流程如下图:
E01. MyBatis基础入门
1. MyBatis基础配通
武技:在子项目中整合 MyBatis 框架
- 准备 MyBatis 测试数据:
-- db
create database mybatis character set utf8mb4;
use mybatis;
-- table
create table clazz
(
id bigint auto_increment comment '主键',
clazz_name varchar(128) not null default '' comment '班级名称',
created datetime not null default current_timestamp comment '创建时间',
updated datetime not null default current_timestamp comment '修改时间',
primary key (id)
) comment '班级表';
create table student
(
id bigint auto_increment comment '主键',
name varchar(128) not null default '' comment '姓名',
gender tinyint not null default 0 comment '性别,0女1男2保密',
phone char(11) not null default '' comment '手机号',
fk_clazz_id bigint comment '班级表外键',
created datetime not null default current_timestamp comment '创建时间',
updated datetime not null default current_timestamp comment '修改时间',
primary key (id)
) comment '学生表';
create table department
(
id bigint auto_increment comment '主键',
dname varchar(128) not null default '' comment '部门名',
created datetime not null default current_timestamp comment '创建时间',
updated datetime not null default current_timestamp comment '修改时间',
primary key (id)
) comment '部门表';
create table employee
(
id bigint auto_increment comment '主键',
ename varchar(128) not null default '' comment '员工名',
phone char(11) not null default '' comment '手机号',
fk_department_id bigint comment '部门表外键',
created datetime not null default current_timestamp comment '创建时间',
updated datetime not null default current_timestamp comment '修改时间',
primary key (id)
) comment '员工表';
-- data
insert into clazz (id, clazz_name)
values (1, 'J2001'),
(2, 'J2002');
insert into student (id, name, gender, phone, fk_clazz_id)
values (1, '赵四', 1, '17700000001', 1),
(2, '刘能', 1, '17700000002', 2);
insert into department (id, dname)
values (1, '设计部'),
(2, '开发部');
insert into employee (id, ename, phone, fk_department_id)
values (1, '赵四', '17700000001', 1),
(2, '刘能', '17700000002', 1),
(3, '广坤', '17700000003', 1),
(4, '刘英', '17700000004', 2);
- 开发
classpath:db.properties
数据源属性文件:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.40.77:3306/mybatis?serverTimezone=Asia/Shanghai\
&useUnicode=true&characterEncoding=utf8\
&useSSL=false&allowPublicKeyRetrieval=true
jdbc.username=joezhou
jdbc.password=joezhou
- 开发
classpath:mybatis.xml
MyBatis 主配文件:
<?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>
<!--从classpath下引入属性文件,不支持 `classpath:` 前缀,后期由Spring代劳-->
<properties resource="db.properties"/>
<!--全局配置-->
<settings>
<!--执行器类型-->
<setting name="defaultExecutorType" value="SIMPLE"/>
</settings>
<!--环境列表标签: 支持配置多环境-->
<environments default="test">
<!--环境标签: 使用JDBC事务(支持提交回滚)-->
<environment id="test">
<!--配置该环境使用JDBC事务管理类,此事务支持提交和回滚-->
<transactionManager type="JDBC"/>
<!--配置该环境使用POOLED连接池,需注入数据源四项-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
- 开发测试类:
package mybatis;
/** @author 周航宇 */
public class MyBatisTest {
/** 测试MyBatis连接是否成功 */
@SneakyThrows
@Test
public void connection() {
// 主配文件的位置: 在创建会话工厂的时候,需要读取主配
String filePath = "mybatis.xml";
// 将主配文件转成输入字节流,创建会话工厂的时候用
InputStream resource = Resources.getResourceAsStream(filePath);
// 通过SqlSessionFactoryBuilder创建SqlSessionFactory,创建时必须读取主配文件
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
.build(resource);
// 通过SqlSessionFactory开启一个具有事务保护的session会话,用于和数据库打交道
// 若使用 `sessionFactory.openSession(true)` 则表示开启一个没有事务保护的session会话
SqlSession sqlSession = sessionFactory.openSession();
// 从SqlSession会话中获取一个连接
Connection connection = sqlSession.getConnection();
// 判断连接是否成功
System.out.println(connection.isClosed() ? "连接失败" : "连接成功");
// 关闭会话,清空一级缓存,可使用 `try-with-resource` 结构
sqlSession.close();
}
}
2. MyBatis工具封装
心法:封装 MyBatis 工具时需要考虑到 SqlSessionFactoryBuilder, SqlSessionFactory, SqlSession 三个核心对象。
核心对象 | 描述 |
---|---|
SqlSessionFactoryBuilder | 用于创建 session 工厂,用完即删,建议设置为局部变量 |
SqlSessionFactory | 可以重复使用,但不该被重复创建,建议以单例模式来管理 |
SqlSession | 每个线程都该独享一个 session 会话,不建议被封装 |
武技:封装 MyBatisUtil 工具类
1.开发 MyBatisUtil 工具类:
package com.joezhou.util;
/** @author 周航宇 */
public class MyBatisUtil {
/** 开发工厂属性: 饱汉单例不赋初值 */
private static volatile SqlSessionFactory factory;
/**
* 获取单例的session工厂实例
* @param resource 主配文件的classpath位置,字符串
* @return 单例的session工厂实例
*/
@SneakyThrows
public static SqlSessionFactory getFactory(String resource) {
// 双重检查锁: DCL第1个if检查用于避免后续线程的加锁接锁开销
if (factory == null) {
// 双重检查锁: DCL锁用于避免线程争抢,毁坏单例效果
synchronized (MyBatisUtil.class) {
// 双重检查锁: DCL第2个if检查用于使用饱汉单例模式构建工厂实例
if (factory == null) {
// 返回主配的字节流对象,创建Session工厂需要
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建Session工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
}
}
// 返回Session工厂
return factory;
}
}
- 测试 MyBatisUtil 工具类:
package mybatis;
/** @author 周航宇 */
public class MyBatisTest {
/** 测试MyBatisUtil工具 */
@SneakyThrows
@Test
public void myBatisUtil() {
// 主配文件的位置: 在创建会话工厂的时侯,需要读取主配
String filePath = "mybatis.xml";
// 使用MyBatisUtil工具获取一个单例的sessionFactory
SqlSessionFactory sessionFactory = MyBatisUtil.getFactory("mybatis.xml");
// 通过SqlSessionFactory开启一个具有事务保护的session会话,用于和数据库打交道
SqlSession sqlSession = sessionFactory.openSession();
// 从SqlSession会话中获取一个连接
Connection connection = sqlSession.getConnection();
// 判断连接是否成功
System.out.println(connection.isClosed() ? "连接失败" : "连接成功");
// 关闭会话,清空一级缓存,可使用 `try-with-resource` 结构
sqlSession.close();
}
}
E02. MyBatis实体设计
1. ORM实体类概念
心法:ORM 全称 Object Relation Mapping 对象关系映射,其中 Object 是指 Java 对象,而 Relation 是指关系型数据库,其核心目标是可以通过操作 Java 对象的方式来操作数据库。
ORM 映射关系如下:
- 类名
class
映射表名table
:如 User 类映射 user 表。 - 成员属性名
field
映射表的字段名column
:如 realName 属性映射 real_name 字段。 - 成员属性类型
javaType
映射表的字段类型jdbcType
:- 如 java.lang.Integer 类型映射 tinyint 或 int 类型。
- 如 java.lang.Long 类型映射 bigint 类型。
- 如 java.lang.String 类型映射 varchar 或 char 类型。
- 如 java.lang.LocalDateTime 类型映射 datetime 类型。
- 类实例
instance
映射表记录record
:如 user 实例映射 row 行。
2. ORM实体类分层
心法:ORM 实体类分层设计方案
3. ORM实体类开发
心法:ORM 实体类设计原则一共有 4 条。
- 类需要使用
implements Serializable
实现序列化标记接口。 - 类中的属性不要使用基本数据类型。
- 类中的属性必须要有
Setter/Getter
方法,可以直接标记@Data
注解。 - 类建议重写
toString()/equals()/hashCode()
等方法。
武技:开发对应 MyBatis 库中全部表的 ORM 实体类
1.开发 ORM 实体类:
package com.joezhou.entity;
/** @author 周航宇 */
@Data
public class Student implements Serializable {
private Long id;
private String realName;
private Integer gender;
private String phone;
private Long fkClazzId;
private LocalDateTime created;
private LocalDateTime updated;
}
package com.joezhou.entity;
/** @author 周航宇 */
@Data
public class Clazz implements Serializable {
private Long id;
private String clazzName;
private LocalDateTime created;
private LocalDateTime updated;
}
package com.joezhou.entity;
/** @author 周航宇 */
@Data
public class Department implements Serializable {
private Long id;
private String dname;
private LocalDateTime created;
private LocalDateTime updated;
}
package com.joezhou.entity;
/** @author 周航宇 */
@Data
public class Employee implements Serializable {
private Long id;
private String ename;
private String phone;
private Long fkDepartmentId;
private LocalDateTime created;
private LocalDateTime updated;
}
- 在 MyBatis 主配中设置下划线转驼峰:
<!--全局配置-->
<settings>
<!--下划线转小驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
4. ORM实体类别名
心法:MyBatis 支持使用别名代替实体类的类全名,提升编码体验,同时也内置了一些简单常用的数据类型的别名。
MyBatis 内置别名如下:
武技:在 MyBatis 主配中设置全部实体类的别名
<!--整包起别名: 别名不区分大小写-->
<typeAliases>
<package name="com.joezhou.entity"/>
</typeAliases>
E03. MyBatis接口开发
心法:MyBatis 框架中,用于和数据库进行数据交互的数据层分为 Mapper 接口和 Mapper 配置两部分。
1. 开发Mapper接口
心法:Mapper 接口是一个 Java文件,用于编写接口方法并被上层(业务层)调用。
武技:开发数据层 Java 代码
- 开发全部表的 Mapper 接口:
package com.joezhou.mapper;
/** @author 周航宇 */
public interface ClazzMapper {
}
package com.joezhou.mapper;
/** @author 周航宇 */
public interface StudentMapper {
}
package com.joezhou.mapper;
/** @author 周航宇 */
public interface DepartmentMapper {
}
package com.joezhou.mapper;
/** @author 周航宇 */
public interface EmployeeMapper {
}
2. 开发Mapper配置
心法:Mapper 配置文件是一个 XML 文件,用于开发和配置 SQL 语句。
Mapper 配置文件要求:
- Mapper 配置文件默认必须和 Mapper 接口同名同包。
- Mapper 配置文件中必须使用
<mapper namespace="">
指向对应的接口。 - Mapper 配置文件所在的目录必须一层一层创建,而不能一次性创建。
武技:开发数据层 XML 代码
- 开发全部表的 Mapper 配置:
<!--com/joezhou/mapper/ClazzMapper.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">
<!--namespace 必须指向对应接口类全名-->
<mapper namespace="com.joezhou.mapper.ClazzMapper">
</mapper>
<!--com/joezhou/mapper/StudentMapper.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">
<!--namespace 必须指向对应接口类全名-->
<mapper namespace="com.joezhou.mapper.StudentMapper">
</mapper>
<!--com/joezhou/mapper/DepartmentMapper.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">
<!--namespace 必须指向对应接口类全名-->
<mapper namespace="com.joezhou.mapper.DepartmentMapper">
</mapper>
<!--com/joezhou/mapper/EmployeeMapper.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">
<!--namespace 必须指向对应接口类全名-->
<mapper namespace="com.joezhou.mapper.EmployeeMapper">
</mapper>
3. 扫描Mapper接口
武技:如果 Mapper 接口不被扫描,程序是无法发现它的。
- 在 MyBatis 主配文件中扫描 Mapper 接口:
<!--全局配置-->
<settings>
<!--控制台打印SQL语句-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--接口扫描-->
<mappers>
<!--在Mapper接口和配置文件同名同包时,整包扫描Mapper接口-->
<package name="com.joezhou.mapper"/>
</mappers>
S02. MyBatis单表操作
心法:MyBatis 中的 DML 语句块分别使用
<insert>
,<update>
和<delete>
标签进行编写,后文统称为 DML 标签。
DML 标签常用属性如下:
属性 | 对应接口方法的 | 是否可以省略 |
---|---|---|
id | 方法名 | 不可省略 |
parameterType | 参数类型或别名 | 可以省略 |
resultType | 返回值类型或别名 | DML 操作必须省略,默认返回 int 型值表示影响条目数 |
E01. MyBatis单表添加
心法:MyBatis 中的占位符和拼接符都用于从实体类型的参数中获取指定的属性值。
MyBatis 支持 占位符 和 拼接符 两种写法,区别如下:
符号 | #{ xx } | ${ xx } |
---|---|---|
中文 | 占位符 | 拼接符 |
是否支持连调 | 支持,如 #{user.parent.name} | 支持,如 #{user.parent.name} |
是否补充单引号 | 自动补单引号,没有注入漏洞 | 不会补单引号,存在注入漏洞 |
武技:开发 Clazz 表的单表添加业务
- 开发 Mapper 接口:
package com.joezhou.mapper;
/** @author 周航宇 */
public interface ClazzMapper {
/**
* 添加一条班级记录
*
* @param clazz 班级实体
* @return 影响条目数
*/
int insert(Clazz clazz);
}
- 开发 Mapper 配置:
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--添加一条班级记录-->
<!--useGeneratedKeys="true" 开启主键回注功能-->
<!--keyProperty="id" 将主键回注到实体类参数的 id 字段中-->
<insert id="insert" parameterType="Clazz"
useGeneratedKeys="true" keyProperty="id">
insert into clazz
(clazz_name, created, updated)
values
(#{clazzName}, #{created}, #{updated})
</insert>
- 测试 Mapper 接口:
package mapper;
/** @author 周航宇 */
public class ClazzMapperTest {
@Test
public void insert() {
// 使用 MyBatisUtil 工具获取会话工厂,并通过会话工厂获取一个会话
SqlSession sqlSession = MyBatisUtil.getFactory("mybatis.xml").openSession();
// 从会话中获取Mapper接口(因为主配中已经扫描了所有Mapper接口,所以可以直接获取)
ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);
// 准备参数
Clazz clazz = new Clazz();
clazz.setClazzName("J12141");
clazz.setCreated(LocalDateTime.now());
clazz.setUpdated(LocalDateTime.now());
// 调用Mapper接口方法,进行添加操作(DML操作需要手动提交事务)
System.out.println(clazzMapper.insert(clazz));
sqlSession.commit();
// 测试主键是否自动回注
System.out.println(clazz);
// 关闭会话,释放资源
sqlSession.close();
}
}
E02. MyBatis单表修改
武技:开发 Clazz 表的单表修改业务(按主键修改)
- 开发 Mapper 接口:
package com.joezhou.mapper;
/**
* 按主键修改一条班级记录
*
* @param clazz 班级实体
* @return 影响条目数
*/
int update(Clazz clazz);
- 开发 Mapper 配置:
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--按主键修改一条班级记录-->
<update id="update">
update clazz set
clazz_name = #{clazzName},
created = #{created},
updated = #{updated}
where id = #{id}
</update>
- 测试 Mapper 接口:
package mapper;
/** @author 周航宇 */
public class ClazzMapperTest {
@Test
public void update() {
// 使用 MyBatisUtil 工具获取会话工厂,并通过会话工厂获取一个会话
SqlSession sqlSession = MyBatisUtil.getFactory("mybatis.xml").openSession();
// 从会话中获取Mapper接口(因为主配中已经扫描了所有Mapper接口,所以可以直接获取)
ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);
// 准备参数
Clazz clazz = new Clazz();
clazz.setId(10L);
clazz.setClazzName("05245");
clazz.setUpdated(LocalDateTime.now());
clazz.setCreated(LocalDateTime.now());
// 调用Mapper接口方法,进行修改操作(DML操作需要手动提交事务)
System.out.println(clazzMapper.update(clazz));
sqlSession.commit();
// 关闭会话,释放资源
sqlSession.close();
}
}
1. 使用动态SQL优化
武技:单表修改相关推荐动态标签
where 标签:生成 WHERE 前缀关键字并删除内容中第一个 AND 或 OR 关键字:
<!--等价于 <trim prefix="WHERE", prefixOverrides="AND"> 写法-->
<where>
内容
</where>
if 标签:仅在条件满足 OGNL 表达式时拼接指定 SQL 内容。
<if test="OGNL">
内容
</if>
choose 标签:
- 条件满足 OGNL 表达式时拼接对应的 when 内容(支持编写多个)。
- 条件不满足 OGNL 表达式时拼接 otherwise 内容(只能编写一个)。
<choose>
<when test="OGNL">内容</when>
<when test="OGNL">内容</when>
<otherwise>内容</othersise>
</choose>
set 标签:生成 SET 前缀关键字并删除内容中最后一个英文逗号:
<!--等价于 <trim prefix="SET", suffixOverrides=","> 写法-->
<set>
内容
</set>
武技:测试使用动态标签 set + if 优化单表修改的 SQL
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--按主键修改一条班级记录-->
<update id="update">
update clazz
<set>
<if test="clazzName != null">clazz_name = #{clazzName},</if>
<if test="created != null">created = #{created},</if>
<if test="updated != null">updated = #{updated},</if>
</set>
where id = #{id}
</update>
E03. MyBatis单表删除
心法:当接口参数是简单类型如 int, String 等,则 OGNL 表达式中推荐使用
_parameter
获取该参数,SQL语句中使用#{param1}/#{arg0}
来获取该接口方法中的第 1 个或第 2 个参数。
@Param 别名:MyBatis支持使用 @Param
对接口参数起别名,但此方式在SQL块之间相互调用时会失效,不推荐。
武技:开发 Clazz 表的单表删除方法(按主键删除)
- 开发 Mapper 接口:
package com.joezhou.mapper;
/**
* 按主键删除班级记录
*
* @param id 班级表主键
* @return 影响条目数
*/
int delete(Long id);
- 开发 Mapper 配置:
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--按主键删除一条班级记录-->
<delete id="delete">
delete from clazz where id = #{param1}
</delete>
- 测试 Mapper 接口:
package mapper;
/** @author 周航宇 */
public class ClazzMapperTest {
@Test
public void delete() {
// 使用 MyBatisUtil 工具获取会话工厂,并通过会话工厂获取一个会话
SqlSession sqlSession = MyBatisUtil.getFactory("mybatis.xml").openSession();
// 从会话中获取Mapper接口(因为主配中已经扫描了所有Mapper接口,所以可以直接获取)
ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);
// 调用Mapper接口方法,进行删除操作(DML操作需要手动提交事务)
System.out.println(clazzMapper.delete(9L));
sqlSession.commit();
// 关闭会话,释放资源
sqlSession.close();
}
}
E04. MyBatis批量删除
心法:批量删除业务中,建议使用动态标签
<foreach>
遍历入参并拼接到 SQL 中。
foreach 标签常用属性如下:
<foreach collection="">
:被遍历的元素,支持数组,列表,数组或列表类型的实体属性或 Map 的 key 值等:
- 若被遍历的元素是一个数组,则固定为
array
关键字。 - 若被遍历的元素是一个列表,则固定为
list
关键字。 - 多个参数时替换为
arg0
写法,也可以使用别名。
<foreach item="">
:设置循环中间变量,如 e
,之后在循环内部可以配合使用 ${e}
将其取出。
<foreach open="">
:设置循环开始时拼接的字符串 SQL 代码。
<foreach close="">
:设置循环结束时拼接的字符串 SQL 代码。
<foreach separator="">
:设置拼接符,自动忽略 SQL 语句中多余的拼接符,如最后一个逗号。
|
武技:开发 Clazz 表的批量删除方法(按主键列表删除)
- 开发Mapper接口
package com.joezhou.mapper;
public interface ClazzMapper {
/**
* 按主键列表批量删除班级记录
*
* @param ids 班级主键列表
* @return 影响条目数
*/
int deleteBatch(List<Long> ids);
}
- 开发 Mapper 配置:
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--按主键列表批删班级记录-->
<delete id="deleteBatch">
delete from clazz where
<foreach collection="list" item="e" open="id in (" close=")" separator=",">
${e}
</foreach>
</delete>
- 测试 Mapper 接口:
package mapper;
/** @author 周航宇 */
public class ClazzMapperTest {
@Test
public void deleteBatch() {
// 使用 MyBatisUtil 工具获取会话工厂,并通过会话工厂获取一个会话
SqlSession sqlSession = MyBatisUtil.getFactory("mybatis.xml").openSession();
// 从会话中获取Mapper接口(因为主配中已经扫描了所有Mapper接口,所以可以直接获取)
ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);
// 调用Mapper接口方法,进行批量删除操作(DML操作需要手动提交事务)
System.out.println(clazzMapper.deleteBatch(List.of(1L, 3L, 5L)));
sqlSession.commit();
// 关闭会话,释放资源
sqlSession.close();
}
}
E05. MyBatis批量添加
武技:开发 Clazz 表的批量添加方法
- 开发 Mapper 接口:
package com.joezhou.mapper;
public interface ClazzMapper {
/**
* 批量添加班级记录
*
* @param clazzes 班级记录列表
* @return 影响条目数
*/
int insertBatch(List<Clazz> clazzes);
}
- 开发 Mapper 配置:
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--批量添加班级记录-->
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
INSERT INTO clazz (clazz_name, created, updated)
VALUES
<foreach collection="list" item="clazz" separator=",">
(#{clazz.clazzName}, #{clazz.created}, #{clazz.updated})
</foreach>
</insert>
- 测试 Mapper 接口:
package mapper;
/** @author 周航宇 */
public class ClazzMapperTest {
@Test
public void insertBatch() {
// 使用 MyBatisUtil 工具获取会话工厂,并通过会话工厂获取一个会话
SqlSession sqlSession = MyBatisUtil.getFactory("mybatis.xml").openSession();
// 从会话中获取Mapper接口(因为主配中已经扫描了所有Mapper接口,所以可以直接获取)
ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);
// 准备参数
Clazz clazz1 = new Clazz();
clazz1.setClazzName("J0001");
clazz1.setCreated(LocalDateTime.now());
clazz1.setUpdated(LocalDateTime.now());
Clazz clazz2 = new Clazz();
clazz2.setClazzName("J0002");
clazz2.setCreated(LocalDateTime.now());
clazz2.setUpdated(LocalDateTime.now());
// 调用Mapper接口方法,进行批量添加操作(DML操作需要手动提交事务)
System.out.println(clazzMapper.insertBatch(List.of(clazz1, clazz2)));
sqlSession.commit();
// 测试主键是否自动回注
System.out.println(clazz1);
System.out.println(clazz2);
// 关闭会话,释放资源
sqlSession.close();
}
}
E06. MyBatis批量修改
心法:MyBatis 批量修改业务需要在
db.properties -> url
串的末尾拼接?allowMultiQueries=true
参数,拼接后,方可在SQL语句后面携带;
以实现多语句执行。
武技:开发 Clazz 表的批量修改方法
- 开发 Mapper 接口:
package com.joezhou.mapper;
public interface ClazzMapper {
/**
* 批量修改班级记录
*
* @param clazzes 班级记录列表
* @return 影响条目数
*/
int updateBatch(List<Clazz> clazzes);
}
- 开发 Mapper 配置:语句末尾必须使用
;
进行分割:
<!--com/joezhou/mapper/ClazzMapper.xml-->
<!--批量修改班级记录-->
<update id="updateBatch">
<foreach collection="list" item="clazz">
UPDATE clazz
<set>
<if test="clazz.clazzName != null">
clazz_name = #{clazz.clazzName},
</if>
<if test="clazz.created != null">
created = #{clazz.created},
</if>
<if test="clazz.updated != null">
updated = #{clazz.updated},
</if>
</set>
WHERE id = #{clazz.id};
</foreach>
</update>
- 测试 Mapper 接口:
package mapper;
/** @author 周航宇 */
public class ClazzMapperTest {
@Test
public void updateBatch() {
// 使用 MyBatisUtil 工具获取会话工厂,并通过会话工厂获取一个会话
SqlSession sqlSession = MyBatisUtil.getFactory("mybatis.xml").openSession();
// 从会话中获取Mapper接口(因为主配中已经扫描了所有Mapper接口,所以可以直接获取)
ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);
// 准备参数
Clazz clazz1 = new Clazz();
clazz1.setId(1L);
clazz1.setClazzName("J0001-1");
clazz1.setCreated(LocalDateTime.now());
clazz1.setUpdated(LocalDateTime.now());
Clazz clazz2 = new Clazz();
clazz2.setId(2L);
clazz2.setClazzName("J0002-2");
clazz2.setCreated(LocalDateTime.now());
clazz2.setUpdated(LocalDateTime.now());
// 调用Mapper接口方法,进行批量修改操作(DML操作需要手动提交事务)
System.out.println(clazzMapper.updateBatch(List.of(clazz1, clazz2)));
sqlSession.commit();
// 关闭会话,释放资源
sqlSession.close();
}
}
Java道经第3卷 - 第1阶 - MyBatis(一)
传送门:JB3-1-MyBatis(一)
传送门:JB3-1-MyBatis(二)