Transaction rolled back because it has been marked as rollback-only
Spring事务管理报错:Transaction rolled back because it has been marked as rollback-only
出错代码
算是比较常见的错误了
很多解释说明都云里雾里的
其实比较简单
1 | class ServiceA{ |
上面这段代码就会报错 Transaction rolled back because it has been marked as rollback-only
原因是 Spring 事务管理是通过AOP切入的
ServiceA 的 testA 已经切入
testB 又切入了一次
@Transactional 的默认传播机制是 Propagation propagation() default Propagation.REQUIRED;
等于 testA 和 testB 使用的是同一个事务
testB 抛出异常时 Spring Aop 已经把事务标记为需要回滚
testA 使用同一个事务 try-catch 了 testB 的异常 所以 testA 没有异常 方法结束
testA 提交事务时 由于 testB已经被回滚 所以抛异常
原因
AOP.serviceA.testA -> 进入方法前 开启事务
↓
serviceA.testA -> 方法执行
↓
AOP.serivceB.testB -> 进入方法前 开启事务 读取到已有事务 REQUIRED 继承A的事务
↓
serviceB.testB -> 方法执行 出现异常
↓
AOP.serviceB.testB -> 方法执行后 检测到异常 回滚事务
↓
serviceA.testA -> 方法执行 testB的异常被 try-catch 方法正常结束
↓
AOP.serviceA.testA -> 方法执行后 没有异常 提交事务
其实就是 AOP 切入了两次 A 和 B 使用的是同一个事务
并且 抓取 B 的错误时 B 已经回滚了事务
解决方法
- 指定 testB 的事务传播性为 REQUIRES_NEW (testB单独一个事务 回滚不影响 testA
- 把 testA 中的 try-catch 放到 testB 中 testB返回true false 给 testA 判断
- 从 controller 中分别调用 testA 和 testB