Spring--事务传播行为(REQUIRED / REQUIRES_NEW / NESTED)
🔵 1.
REQUIRED
(默认)🧠 概念:
当前存在事务 → 加入当前事务
当前不存在事务 → 新建事务
事务统一提交或回滚
📌 情况 1:外层无事务 → 启动新事务
➕ 子方法也使用 REQUIRED(新建事务)
// 外层无事务 public void outer() {inner(); // -> 新建事务 }@Transactional(propagation = Propagation.REQUIRED) public void inner() {// 执行数据库写入// 抛出异常将回滚自己新建的事务 }
✅ inner() 自己新建事务 → 异常只影响自身,outer 不受影响。
📌 情况 2:外层有事务 → 子方法加入当前事务
➕ 子方法也使用 REQUIRED(共享事务)
@Transactional public void outer() {inner(); // 加入同一个事务throw new RuntimeException(); // 异常导致整个事务回滚 }@Transactional(propagation = Propagation.REQUIRED) public void inner() {// 写数据库 }
🟥 回滚行为:
outer中出现异常:outer 抛出异常 → outer + inner 全部回滚
inner中出现异常:inner 抛异常未捕获 → 整体回滚
inner中出现异常:inner 抛异常被 outer 捕获 → 也会整体回滚
当 inner () 抛出 RuntimeException 时,Spring 会标记整个事务为 rollback-only,即使 outer () 捕获并处理了异常,在提交时也会强制回滚整个事务 T1。
🔴 总结:
外层是否有事务 inner 事务 是否共享事务 回滚影响 ❌ 无事务 新建事务 否 异常回滚自身 ✅ 有事务 加入事务 是 谁异常谁负责,全局回滚
🟡 2.
REQUIRES_NEW
🧠 概念:
总是开启新事务
如果外层已有事务 → 将其挂起
子方法的事务与外层事务完全隔离
📌 情况 1:外层无事务 → 子方法新建事务
public void outer() {inner(); // 启动新事务 }@Transactional(propagation = Propagation.REQUIRES_NEW) public void inner() {// 正常提交或回滚,与外层无关 }
✅ 单独事务,inner 的提交/回滚不影响 outer。
📌 情况 2:外层有事务 → 子方法新建新事务(挂起外层)
@Transactional public void outer() {inner(); // 新事务,与 outer 不相关throw new RuntimeException(); // outer 回滚,但 inner 成功 }@Transactional(propagation = Propagation.REQUIRES_NEW) public void inner() {// 新事务提交成功 }
🟢 回滚行为:
inner 正常 → 提交成功
outer 抛异常 → 仅回滚 outer,不影响 inner
适合日志写入等场景
📌 情况 3:子事务异常,outer 捕获处理
@Transactional public void outer() {try {inner(); // 抛异常被捕获} catch (Exception e) {System.out.println("记录失败,继续流程");}// outer 继续执行,最终提交 }@Transactional(propagation = Propagation.REQUIRES_NEW) public void inner() {throw new RuntimeException("记录失败"); }
✅ inner 异常回滚,不影响 outer 提交。
🔴 总结:
外层是否有事务 inner 事务 是否共享事务 回滚影响 ❌ 无事务 新建事务 否 inner 控制自己回滚 ✅ 有事务 新建事务,挂起 outer 否 inner 异常不影响 outer,反之也一样
🟢 3.
NESTED
🧠 概念:
有事务 → 创建嵌套事务(Savepoint)
无事务 → 相当于
REQUIRED
依赖父事务 → 嵌套事务提交前父事务回滚,嵌套也回滚
嵌套事务回滚 → 父事务可选择是否继续(局部回滚)
📌 情况 1:外层无事务 → 和 REQUIRED 相同
public void outer() {inner(); // 启动新事务 }@Transactional(propagation = Propagation.NESTED) public void inner() {// 单独控制事务(但其实是新建) }
📌 情况 2:外层有事务,inner 嵌套事务中抛异常
@Transactional public void outer() {try {inner(); // 抛异常} catch (Exception e) {System.out.println("inner failed, outer continues");}// outer 继续执行 }@Transactional(propagation = Propagation.NESTED) public void inner() {throw new RuntimeException("inner error"); }
🟡 如果事务管理器支持 Savepoint(如 DataSourceTransactionManager):
inner 异常 → 回滚到 savepoint,outer 仍可继续提交
实现部分回滚
📌 情况 3:外层事务最终抛异常
@Transactional public void outer() {inner(); // 正常执行throw new RuntimeException("outer failed"); }@Transactional(propagation = Propagation.NESTED) public void inner() {// 执行成功,但最终也回滚 }
🟥 注意:
inner 提交了?不!因为它只是父事务的 savepoint,父事务一旦回滚,嵌套事务也随之回滚
🔴 总结:
外层是否有事务 inner 行为 是否独立提交 回滚行为 ❌ 无事务 新建事务(等价 REQUIRED) 是 自己控制 ✅ 有事务 创建 savepoint ❌ 依附外层事务 inner 可部分回滚,但 outer 回滚则全回滚
✅ 三者对比总结表
传播行为 外层有事务 子事务是否新建 是否和外层隔离 外层异常是否影响子事务 子事务异常是否影响外层事务 REQUIRED 否 ✅ 新建事务 ❌ 不隔离 ❌ 不影响(自身控制) ❌ 不影响(自身控制) REQUIRED 是 ❌ 加入外层事务 ❌ 不隔离 ✅ 影响 ✅ 影响 REQUIRES_NEW 否 ✅ 新建事务 ✅ 完全隔离 ❌ 不影响 ❌ 不影响(除非显式传播) REQUIRES_NEW 是 ✅ 新建事务(挂起外层) ✅ 完全隔离 ❌ 不影响 ❌ 不影响 NESTED 否 ✅ 新建事务 ❌ 不隔离 ❌ 不影响 ❌ 不影响 NESTED 是 创建 savepoint ❌ 局部隔离 ✅ 影响全部 ❌ 可被捕获实现局部回滚