Spring @Transactional 没回滚?按代理调用、异常和传播行为排查

代码上写了 @Transactional,数据库却留下了本应撤销的数据。排查时先确认事务有没有生效,再确认异常是否触发回滚,最后看实际操作是否属于同一个事务。

先查调用有没有经过代理

Spring 默认代理模式会拦截从外部经过代理进入的方法调用。同一个对象内部直接调用另一个带注解的方法,不会因为那个方法上的注解而自动新增事务拦截。

假设 createOrder 在类内部直接调用 saveOrder,只有 saveOrder 标了注解。需要检查入口是否通过代理,以及当前是否已经有其他事务。看到注解不能推断这一次调用受到了它的管理。Spring 官方说明明确说明了自调用的限制。

自己 new 出来的对象,同样需要检查是否脱离容器管理。方法可见性还受代理类型与版本影响。Spring 6 的类代理可支持部分非 public 方法,接口代理有其要求,不能把"所有非 public 方法都失效"当成通用结论。

异常有没有传到事务拦截器

传统默认规则下,RuntimeException 与 Error 触发回滚,普通受检异常不会自动触发。可以按业务设置 rollbackFor。Spring 6.2 起还支持调整全局默认回滚策略,因此需要查看当前项目的真实配置。

假设数据库操作之后抛出了异常,但方法内部 catch 住并正常返回。代理可能看不到应触发回滚的异常。仅打印日志,无法表达业务希望回滚的决定。

处理方式应与业务语义一致,需要回滚就通过合适的异常或回滚标记表达,同时避免把应该正常处理的业务状态全部转成异常。

传播行为决定共享哪些事务

REQUIRED 在已有事务中通常参与同一个物理事务。内部参与者设置 rollback-only 后,外层即使捕获异常继续执行,也可能在最终提交时收到 UnexpectedRollbackException。

REQUIRES_NEW 使用独立事务。内层已提交的记录,不会因为外层随后回滚而自动撤销。外层占着连接再申请内层连接,还需要考虑连接池容量与并发压力。

NESTED 通常依赖保存点以及事务管理器和资源的支持。不能仅凭注解名称,就认为所有数据访问技术都能按同样方式回滚内层操作。

这些规则可以进一步核对传播行为文档。

本地事务管理哪些资源

数据库回滚不会撤回已经发送的邮件,也不一定取消外部 HTTP 请求。如果订单事务里调用了外部支付接口,数据库失败以后,外部扣款结果必须单独核对。

这类流程需要明确幂等、状态核对与补偿安排。把全部调用放在带注解的方法中,不会自动让它们成为一个跨系统原子操作。

验证时通过真实服务入口调用,准备异常发生在写入前后、异常被捕获、独立内层提交等场景,再检查最终数据库状态。测试自身包裹的事务可能影响观察,需要确认验证的是生产调用方式。

沿着调用入口、异常处理和资源范围逐步检查,通常比反复增删注解更容易找到原因。

我是程序员Sunday,本文相关的完整解析收录在 sunday面试指南,可继续阅读《Spring 的 @Transactional 为什么会失效?事务传播行为怎么选?》。

相关推荐
付威20231 小时前
我用 100 行核心代码,做了一个能接入飞书的 Hermes 式智能体
人工智能·后端
java资料站1 小时前
案例:Spring Ai/Alibaba《模拟面试器》项目案例
人工智能·spring·面试
苏三说技术1 小时前
为什么越来越多人用 ZXing?
后端
冰暮流星1 小时前
sql之is null 运算符
java·数据库·sql
Rain的Java大神之路1 小时前
🔥13年Java老兵转型AI Agent:90%的人挂在同一个坑,根本不用学Python!(万字实战复盘,建议收藏)
java·后端·面试
yuniko-n1 小时前
【Java】关于容器选型:Deque、PriorityQueue、LinkedList
java·开发语言
IT小番茄1 小时前
用Codex搭可视化大屏工作流 15个行业场景设计稿看完直接抄作业
后端
by————组态1 小时前
Ricon组态适用领域全景解析:工业制造、能源、市政民生与智慧城市四大场景落地实践
后端·物联网·数学建模·智慧城市·能源·制造·组态