事务不回滚最常见原因是try-catch吞掉异常:spring只对未捕获的runtimeexception和error回滚,catch后未重抛或手动回滚则事务提交;需检查@transactional方法中catch块是否遗漏re-throw或setrollbackonly,并确认方法public、无自调用、异常类型匹配rollbackfor配置。

直接看代码里有没有 try-catch 块把异常“吞掉”了——这是事务不回滚最常见也最容易被忽略的原因。Spring 默认只对未捕获的 RuntimeException 和 Error 回滚,一旦你在方法内部用 catch 捕获了异常又没重新抛出,Spring 就认为方法执行成功,会提交事务。
检查 catch 块是否遗漏了 re-throw 或手动回滚
重点扫描所有加了 @Transactional 的方法,尤其是业务逻辑较重、涉及多步数据库操作的地方。只要看到 try { ... } catch (Exception e) { log.error(...); } 这类结构,就要警惕:
- 如果 catch 后没有
throw e、throw new RuntimeException(e)或类似语句,事务一定不会回滚 - 即使加了
@Transactional(rollbackFor = Exception.class),只要异常被 catch 住且没抛出,照样失效 - 日志里可能只打印错误,但控制台或监控看不到异常传播路径,容易误判为“没出错”
确认异常实际是否逃逸出方法边界
事务回滚的前提是异常最终“冒泡”到代理方法的出口。你可以这样验证:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 在 catch 块末尾加一句
log.info("异常已处理,方法将正常返回");—— 如果这条日志出现,基本说明事务已提交 - 在数据库层面观察:比如先删一条记录,再在 catch 前故意触发异常,看删的数据是否还在;若存在,就是被提交了
- 开启 Spring 事务调试日志:
logging.level.org.springframework.transaction=DEBUG,看日志中是否有Completing transaction而非Triggering rollback
快速修复:两种稳妥做法任选其一
不需要重构整个调用链,改几行就能生效:
-
显式抛出运行时异常:在 catch 里写
throw new RuntimeException(e);(推荐,语义清晰) -
手动标记回滚:在 catch 中加入
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();,强制当前事务只能回滚
顺便排查其他配套问题
单靠解决 catch 问题还不够,要同步确认:
- 该方法是不是
public?非 public 方法上加@Transactional注解无效 - 是不是在同一个类里“this.xxx()”调用的?自调用绕过代理,事务不生效
- 抛出的异常类型是否匹配
rollbackFor设置?比如配置了rollbackFor = BusinessException.class,结果抛的是SQLException,也不回滚
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










