在Spring中,事务的传播行为(Transaction Propagation Behavior)决定了方法之间调用时,事务应该如何传递和处理。Spring共支持 7种 传播机制,每种都有不同的语义和适用场景。
✅ Spring 中的7种事务传播机制及示例
下面以统一格式说明这7种传播机制,并配合代码示例说明其使用场景以及回滚的情况。
1. Propagation.REQUIRED(默认)
- 含义:如果当前存在事务,则加入该事务;如果没有事务,则新建一个事务。
- 特点:这是最常用的传播行为,适用于大多数业务操作。
- 回滚情况:内部方法抛异常未捕获,外部方法也会回滚。
示例:
@Transactional(propagation = Propagation.REQUIRED)
public void serviceA() {
// 插入用户信息
userDao.insertUser();
// 调用serviceB
serviceB(); // 在同一个事务中执行
}
@Transactional(propagation = Propagation.REQUIRED)
public void serviceB() {
// 插入订单信息
orderDao.insertOrder();
if (someErrorCondition) {
throw new RuntimeException("插入订单失败");
}
}
结果:
serviceB()抛出异常 → 整个事务(包括serviceA()的插入用户)都会回滚。
2. Propagation.SUPPORTS
- 含义:如果当前存在事务,则加入事务;否则以非事务方式执行。
- 适合:只读操作或对事务不敏感的操作。
- 回滚情况:不会主动开启事务,也不会触发回滚。
示例:
@Transactional(propagation = Propagation.SUPPORTS)
public void queryData() {
// 查询数据
userDao.selectUserById(1L);
}
结果:
- 如果是事务上下文中调用:查询会参与事务。
- 如果是非事务调用:则以非事务方式执行,不涉及回滚。
3. Propagation.MANDATORY
- 含义:必须存在事务,否则抛出异常。
- 适合:强制要求方法必须运行在事务中。
- 回滚情况:由外部事务控制。
示例:
@Transactional(propagation = Propagation.MANDATORY)
public void updateWithMandatory() {
userDao.updateUserInfo();
}
结果:
- 若无事务调用此方法 → 抛出
IllegalTransactionStateException - 若有事务调用 → 正常参与事务,外部事务回滚时也一起回滚。
4. Propagation.REQUIRES_NEW
- 含义:不管当前是否存在事务,都新建事务,并挂起当前事务(如果有)。
- 适合:需要独立事务的方法(如日志记录、审计等)。
- 回滚情况:内部事务回滚不影响外部事务,但外部事务回滚会影响内部事务。
示例:
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
userDao.insertUser();
try {
innerMethod(); // 独立事务
} catch (Exception e) {
// 捕获异常后继续执行
}
otherDao.insertOther(); // 即使inner回滚,这里仍可提交
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
logDao.insertLog();
if (someErrorCondition) {
throw new RuntimeException("日志插入失败");
}
}
结果:
innerMethod()抛出异常 → 它自己的事务回滚,不影响outerMethod()的其他操作。outerMethod()回滚 →innerMethod()也会被回滚(因为它是外层事务的一部分)。
5. Propagation.NOT_SUPPORTED
- 含义:以非事务方式执行,如果当前存在事务,则暂停它。
- 适合:性能优先的只读操作或无需事务的方法。
- 回滚情况:没有事务,无法回滚。
示例:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void fastQuery() {
userDao.selectAllUsers(); // 不参与事务
}
结果:
- 即使是在事务中调用,这个方法也不会参与事务。
- 数据库一致性可能不受保证。
6. Propagation.NEVER
- 含义:不能在事务中执行,否则抛出异常。
- 适合:明确禁止事务的方法。
- 回滚情况:不会执行,直接抛异常。
示例:
@Transactional(propagation = Propagation.NEVER)
public void nonTransactionalMethod() {
System.out.println("This should not be called in a transaction.");
}
结果:
- 如果在事务中调用 → 抛出
IllegalTransactionStateException - 否则正常执行
7. Propagation.NESTED
- 含义:如果当前存在事务,则嵌套在其中作为一个子事务(通过保存点实现);否则新建事务。
- 适合:部分回滚需求。
- 回滚情况:内部事务可以独立回滚而不影响外部事务。
示例:
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
userDao.insertUser(); // 外部事务开始
try {
innerMethod(); // 嵌套事务
} catch (Exception e) {
// 可以选择只回滚 innerMethod 的操作
}
otherDao.insertOther(); // 继续执行
}
@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
orderDao.insertOrder();
if (someErrorCondition) {
throw new RuntimeException("插入订单失败");
}
}
结果:
innerMethod()抛出异常 → 只回滚到保存点,不影响user插入。outerMethod()抛出异常 → 全部回滚,包括innerMethod()的更改。
📝 总结对比表
| 传播行为 | 当前无事务 | 当前有事务 | 是否新事务 | 是否可回滚 | 特点 |
|---|---|---|---|---|---|
REQUIRED | 新建事务 | 加入已有事务 | 否 | 是 | 默认值,最常用 |
SUPPORTS | 非事务执行 | 加入已有事务 | 否 | 否 | 可选事务 |
MANDATORY | 报错 | 加入已有事务 | 否 | 是 | 强制要求事务 |
REQUIRES_NEW | 新建事务 | 挂起现有事务,新建事务 | 是 | 是 | 独立事务,互不影响 |
NOT_SUPPORTED | 非事务执行 | 挂起现有事务,非事务执行 | 否 | 否 | 提高性能 |
NEVER | 非事务执行 | 报错 | 否 | 否 | 禁止事务 |
NESTED | 新建事务 | 在当前事务内嵌套(保存点) | 否(子事务) | 是(局部) | 支持局部回滚 |