哪些情况会导致事务注解失效?
未标记
考查重点:代理路径与异常、资源边界。先核调用是否经代理,再查回滚异常、传播和资源边界,自调用或吞异常常使行为不符预期
本题目录
参考答案
核心回答
先区分两类现象:事务增强根本没有生效,或者事务已经建立,但回滚规则、传播方式和资源范围不符合预期。以 Spring Framework 6.2 的代理式事务为例,重点检查是否经过代理、方法能否被代理、异常是否触发回滚,以及操作是否真的加入同一个事务。
没有进入事务增强
绕过代理:同类内用 this 自调用,不会重新经过代理;直接 new 的对象或没有交给 Spring 管理的对象,也不会自动获得事务增强。应把需要独立事务边界的行为放在明确的 Bean 调用边界中,并确认调用者拿到的是代理。
代理与方法限制:类代理不能通过覆盖增强 private、final 方法,final 类也受限制;接口代理要求事务方法是代理接口中的 public 方法。但不能笼统说“非 public 全失效”:Spring 6 的类代理默认也可支持 protected 和包可见方法,仍需结合具体代理配置判断。
基础设施未启用:只有注解不够,还需要事务管理配置、合适的事务管理器以及正确的数据访问资源。多数据源下选择错管理器,可能只保护了另一套连接。
有事务但结果不符合预期
默认规则通常对 RuntimeException 和 Error 回滚,对受检异常不自动回滚;可以配置具体回滚规则。Spring 6.2 还支持调整全局默认规则,因此排查时要看项目实际设置。方法内部捕获异常并正常返回时,拦截器可能看不到需要回滚的异常;但底层已把事务标为 rollback-only 的情况又可能在提交时失败。
传播行为也会改变边界。例如 REQUIRES_NEW 是独立事务,外层回滚不自动撤销已提交的内层;NOT_SUPPORTED 暂停事务。它们可能是配置符合定义,却与业务预期不一致,不能一概称为注解没起作用。
普通线程绑定事务不会自动覆盖新建线程或线程池里的工作;响应式事务使用另一种上下文模型,也不能混用。数据库和存储引擎必须支持相关事务,连接还需正确参与其中。上传对象存储、发送外部请求等动作,通常不在本地数据库事务的原子范围内。
怎样定位
检查代理类型、事务管理器、调用边界和实际连接,开启有范围的事务诊断;在真实数据源集成测试中制造异常,确认写入和回滚结果。测试也要覆盖提交路径,防止测试框架自己的事务回滚掩盖应用边界问题。
数据库事务之外的订单、积分、消息等一致性,还需根据边界选择可靠事件、幂等或补偿。
参考资料
- 国内:JavaGuide / Snailclimb:Spring 事务详解:参考事务使用注意事项,按代理、异常和资源范围组织正文的事务失效排查。
- 国内:JavaGuide / Snailclimb:IoC 与 AOP 详解:借鉴代理机制,解释正文中绕过 Bean 代理的自调用为何不会重新应用事务增强。
- 国内:JavaGuide / Snailclimb:Spring 常见注解:事务:参考事务注解作用范围与方法级配置覆盖,说明正文中实际生效的回滚属性需要按调用和配置判断。
- 国外:Spring:Using @Transactional, Spring6.2:官方说明核准Spring6类代理对非public方法的支持,并交代多事务管理器和全局回滚配置。
- 国外:Spring:Rolling Back a Declarative Transaction, Spring6.2:依据异常与回滚规则的定义,区分正文中增强未执行和增强执行后按配置提交的情况。


