文章目录
-
- 一、事务隔离级别
-
- [1.1 MySQL 事务隔离级别](#1.1 MySQL 事务隔离级别)
- [1.2 Spring 事务隔离级别](#1.2 Spring 事务隔离级别)
- [二、Spring 事务传播机制](#二、Spring 事务传播机制)
-
- [2.1 事务传播机制概念](#2.1 事务传播机制概念)
- [2.2 事务的传播机制分类](#2.2 事务的传播机制分类)
- [2.3 Spring 事务传播机制使用](#2.3 Spring 事务传播机制使用)
-
- [2.3.1 REQUIRED(加入事务)](#2.3.1 REQUIRED(加入事务))
- [2.3.2 REQUIRES_NEW(新建事务)](#2.3.2 REQUIRES_NEW(新建事务))
- [2.3.3 NEVER(不支持当前事务,抛异常)](#2.3.3 NEVER(不支持当前事务,抛异常))
- [2.3.4 NESTED(嵌套事务)](#2.3.4 NESTED(嵌套事务))
- [2.4 NESTED 和 REQUIRED 的区别](#2.4 NESTED 和 REQUIRED 的区别)

一、事务隔离级别
1.1 MySQL 事务隔离级别
SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:
-
读未提交(READ UNCOMMITTED) :读未提交,也叫未提交读。该隔离级别的事务可以看到其他事务中未提交的数据。
因为其他事务未提交的数据可能会发生回滚,但该隔离级别却可以读到,这种级别下读到的数据被称为脏数据 ,对应的问题称为脏读。
-
读提交(READ COMMITTED) :读已提交,也叫提交读。该隔离级别的事务能读取到已经提交事务的数据,不会出现脏读问题。
但由于事务执行过程中可读取其他事务提交的结果,同一 SQL 查询在不同时间可能得到不同结果,这种现象称为不可重复读。
-
可重复读(REPEATABLE READ) :事务不会读到其他事务对已有数据的修改(即使其他事务已提交),能确保同一事务多次查询结果一致。
但其他事务新插入的数据可被感知,可能引发幻读 问题(例如:事务中多次查询同一条件数据,其他事务插入符合条件的新数据后,本事务查询结果行数不变,但插入时因唯一约束失败)。
可重复读是 MySQL 的默认事务隔离级别。
-
串行化(SERIALIZABLE) :事务最高隔离级别,强制事务按顺序执行,避免冲突,可解决脏读、不可重复读和幻读问题。
但执行效率极低,实际使用场景较少。
事务隔离级别与并发问题对应关系:
| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交(READ UNCOMMITTED) | ✅ | ✅ | ✅ |
| 读提交(READ COMMITTED) | ❌ | ✅ | ✅ |
| 可重复读(REPEATABLE READ) | ❌ | ❌ | ✅ |
| 串行化(SERIALIZABLE) | ❌ | ❌ | ❌ |
1.2 Spring 事务隔离级别
Spring 中事务隔离级别有 5 种,本质是对数据库隔离级别的抽象,通过 @Transactional 注解的 isolation 属性配置:
- Isolation.DEFAULT :以连接数据库的事务隔离级别为主(默认值),例如 MySQL 对应
REPEATABLE READ,Oracle 对应READ COMMITTED。 - Isolation.READ_UNCOMMITTED :对应 SQL 标准的
READ UNCOMMITTED,允许脏读、不可重复读、幻读。 - Isolation.READ_COMMITTED :对应 SQL 标准的
READ COMMITTED,禁止脏读,允许不可重复读、幻读。 - Isolation.REPEATABLE_READ :对应 SQL 标准的
REPEATABLE READ,禁止脏读、不可重复读,允许幻读。 - Isolation.SERIALIZABLE :对应 SQL 标准的
SERIALIZABLE,禁止所有并发问题,性能最低。
Spring 隔离级别枚举定义

Spring 隔离级别配置示例:通过 @Transactional 的 isolation 属性显式指定隔离级别。
java
@RestController
@RequestMapping("/trans")
public class IsolationController {
@Transactional(isolation = Isolation.READ_COMMITTED)
@RequestMapping("/r3")
public String r3(String name, String password) {
// 业务逻辑(例如用户注册)
// userService.registryUser(name, password);
return "r3";
}
}
二、Spring 事务传播机制
2.1 事务传播机制概念
事务传播机制是指:多个被 @Transactional 修饰的事务方法存在调用关系时,事务在方法间的传递规则。
例如:方法 A(含事务)调用方法 B(含事务),B 是加入 A 的事务,还是创建新事务?这一规则由事务传播机制决定。
- 事务隔离级别:解决"多个事务同时操作同一数据库"的并发问题。
- 事务传播机制:解决"一个事务在多个方法节点间传递"的协作问题。
2.2 事务的传播机制分类
Spring 事务传播机制通过 @Transactional 注解的 propagation 属性指定,共 7 种,对应 Propagation 枚举:
-
Propagation.REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建新事务。
-
Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式运行。
-
Propagation.MANDATORY(强制性):如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
-
Propagation.REQUIRES_NEW :创建新事务;如果当前存在事务,则将当前事务挂起。
无论外部是否有事务,修饰的内部方法均开启独立事务,事务间互不干扰。
-
Propagation.NOT_SUPPORTED:以非事务方式运行;如果当前存在事务,则将当前事务挂起。
-
Propagation.NEVER:以非事务方式运行;如果当前存在事务,则抛出异常。
-
Propagation.NESTED :如果当前存在事务,则创建"嵌套事务"(作为当前事务的子事务)运行;如果当前没有事务,则等价于
REQUIRED。
Spring 传播机制枚举定义

2.3 Spring 事务传播机制使用
2.3.1 REQUIRED(加入事务)
场景需求:用户注册(插入用户数据)+ 记录操作日志(插入日志数据),日志插入时出现异常,观察事务是否回滚。
代码实现
- Controller 层(开启事务):
java
@RequestMapping("/propaga")
@RestController
public class PropagationController {
@Autowired
private UserService userService;
@Autowired
private LogService logService;
// 事务传播机制:REQUIRED(默认)
@Transactional(propagation = Propagation.REQUIRED)
@RequestMapping("/p1")
public String p1(String name, String password) {
// 1. 用户注册(调用 UserService,加入当前事务)
userService.registryUser(name, password);
// 2. 记录日志(调用 LogService,加入当前事务,故意抛出异常)
logService.insertLog(name, "用户注册");
return "操作完成";
}
}
- UserService 层(加入事务):
java
@Slf4j
@Service
public class UserService {
@Autowired
private UserInfoMapper userInfoMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void registryUser(String name, String password) {
// 插入用户数据
userInfoMapper.insert(name, password);
log.info("用户数据插入成功");
}
}
- LogService 层(加入事务,故意抛出异常):
java
@Slf4j
@Service
public class LogService {
@Autowired
private LogInfoMapper logInfoMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void insertLog(String name, String op) {
// 故意抛出算术异常
int a = 10 / 0;
// 记录日志(代码不会执行)
logInfoMapper.insertLog(name, op);
}
}
执行结果:数据库无任何数据插入。
流程描述
- Controller 的
p1方法开启事务; userService.registryUser加入p1的事务,用户数据插入成功;logService.insertLog加入p1的事务,抛出异常导致事务回滚;- 由于用户插入和日志插入属于同一事务,回滚后用户数据也被撤销。
2.3.2 REQUIRES_NEW(新建事务)
场景需求:修改上述场景的传播机制为 REQUIRES_NEW,确保日志插入异常不影响用户注册。
代码修改
- UserService 层(新建事务):
java
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void registryUser(String name, String password) {
userInfoMapper.insert(name, password);
log.info("用户数据插入成功");
}
- LogService 层(新建事务,故意抛出异常):
java
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertLog(String name, String op) {
int a = 10 / 0; // 异常
logInfoMapper.insertLog(name, op);
}
执行结果:
- 用户表:数据插入成功(
UserService的事务独立执行,无异常); - 日志表:数据插入失败(
LogService的事务抛出异常,独立回滚)。
核心结论:
REQUIRES_NEW 修饰的方法会开启独立事务,与外部事务互不干扰,适用于"不希望事务间相互影响"的场景(如:核心业务与日志记录分离)。
2.3.3 NEVER(不支持当前事务,抛异常)
场景需求:修改UserService中对应的方法的事务传播机制为Propagation.NEVER
代码修改
java
@Slf4j
@Service
public class UserService {
@Autowired
private UserInfoMapper userInfoMapper;
// 传播机制:NEVER(禁止当前存在事务)
@Transactional(propagation = Propagation.NEVER)
public void registryUser(String name, String password) {
userInfoMapper.insert(name, password);
}
}
执行结果:程序报错,数据库无数据插入。异常信息示例:
2.3.4 NESTED(嵌套事务)
场景需求:修改UserService和LogService中对应的方法的事务传播机制为 Propagation.NESTED
代码实现
- UserService 层(嵌套事务):
java
@Transactional(propagation = Propagation.NESTED)
public void registryUser(String name, String password) {
userInfoMapper.insert(name, password);
}
- LogService 层(嵌套事务,故意抛出异常):
java
@Transactional(propagation = Propagation.NESTED)
public void insertLog(String name, String op) {
int a = 10 / 0; // 异常
logInfoMapper.insertLog(name, op);
}
执行结果:数据库无任何数据插入。
流程描述
- Controller 的
p1方法开启父事务; userService.registryUser作为子事务(嵌套父事务),用户数据插入成功;logService.insertLog作为子事务(嵌套父事务),抛出异常后回滚子事务;- 由于子事务异常未处理,向上传递导致父事务回滚,用户数据也被撤销。
2.4 NESTED 和 REQUIRED 的区别
核心差异:是否支持"部分回滚"
区别:
- 事务全部执行成功时,二者的结果一致。
- 事务部分执行成功时:REQUIRED加入事务会导致整个事务全部回滚;NESTED嵌套事务可实现局部回滚,不会影响上一个方法的执行结果。
嵌套事务(NESTED)通过保存点(Savepoint) 实现部分回滚,而 REQUIRED 加入事务后无保存点,回滚则整个事务失效。
本质区别
| 特性 | NESTED(嵌套事务) | REQUIRED(加入事务) |
|---|---|---|
| 事务关系 | 父事务 + 子事务(有保存点) | 同一事务(无保存点) |
| 子事务异常回滚 | 仅回滚子事务,不影响父事务 | 回滚整个事务 |
| 父事务异常回滚 | 子事务随父事务一起回滚 | 整个事务回滚 |
| 适用场景 | 需部分回滚的业务(如:核心步骤+非核心步骤) | 需完全一致的业务(如:转账的扣款+加款) |