事务嵌套时异常被try-catch吞掉会导致外层误提交并抛出rollback-only错误,根本原因是未将失败信号传递给事务管理器;应删掉无意义catch、重抛受管异常、合理选用REQUIRES_NEW或NESTED传播行为、必要时调用setRollbackOnly()显式回滚,并对受检异常配置rollbackFor。

事务嵌套时异常被 try-catch 吞掉,导致外层事务误判为“执行成功”而尝试提交,最终抛出 Transaction rolled back because it has been marked as rollback-only ——这本质不是异常没被捕获,而是捕获后没把“失败信号”传给事务管理器。
别让 catch 成为事务的“断点”
Spring 的事务回滚由事务切面在方法退出时根据异常类型和传播行为决定。一旦你在事务方法里用 catch 把运行时异常“吃掉”,又不重抛、也不显式标记回滚,事务管理器就认为一切正常,到 commit 阶段才发现上下文已被内层设为 rollback-only,于是报错。
- 删掉无意义的
try-catch:如果捕获后只是打日志+返回,不如直接让异常上抛 - 必须捕获时,要重抛一个被
@Transactional(rollbackFor = ...)覆盖的异常 - 若需保留原异常语义,可用
throw new RuntimeException(e)或自定义业务异常并配置rollbackFor
用对传播行为,从源头隔离异常影响
默认 REQUIRED 让内外层共用一个事务上下文,一损俱损。根据业务一致性要求选更合适的传播方式:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- REQUIRES_NEW:内层开启全新事务,失败只回滚自己,外层不受影响。适合发通知、写日志等弱一致性操作
-
NESTED:基于数据库 savepoint 实现真正嵌套,内层异常仅回滚到保存点,外层可继续执行。要求数据库支持(MySQL/PostgreSQL/Oracle 均支持),且比
REQUIRES_NEW更轻量 - 避免在
REQUIRED下做“局部补偿”幻想——只要在一个事务里,任何未处理异常都会导致整体回滚
手动接管回滚决策(兜底方案)
当业务逻辑强制要求捕获异常、又不能改传播行为时,必须主动通知事务管理器:“这个事务该回滚了”:
立即学习“Java免费学习笔记(深入)”;
- 在
catch块中调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() - 确保当前线程处于事务上下文中(即该方法本身被
@Transactional修饰) - 注意:此操作不可逆,调用后即使后续代码无异常,事务也只会回滚
受检异常要显式声明回滚
Spring 默认不对 Exception 及其子类(如 IOException、SQLException)回滚。若业务逻辑中需因这类异常回滚,必须明确配置:
-
@Transactional(rollbackFor = Exception.class)(粗粒度) -
@Transactional(rollbackFor = {CustomBizException.class, SQLException.class})(精准控制) - 仅配置还不够:捕获后仍需重抛或
setRollbackOnly(),否则事务照样提交

















