title: @Transactional 失效场景 description: 深度解析 @Transactional 注解失效的常见原因,包括自调用、异常处理、访问权限、代理机制等核心问题及其解决方案。
@Transactional 失效场景
候选人小冯在面试京东 P6 时,面试官问道:
"@Transactional 一定会生效吗?"
小冯说:"不一定..."
面试官追问:"什么情况下会失效?"
小冯说:"private 方法...还有 self 调用..."
面试官:"还有呢?"
小冯说不出来了。
【面试官心理】 这道题我用来测试候选人对 Spring 事务的实战理解。知道 private 方法和自调用失效的人不少,但能说全所有场景的凤毛麟角。这道题能答出 5 种以上的,基本都在生产环境踩过这些坑。
一、核心问题 🔴
1.1 问题拆解
第一层:基础认知
- "@Transactional 标注的方法一定会开启事务吗?"
- "什么情况下 @Transactional 会失效?"
第二层:失效场景
- "为什么 private 方法不会生效?"
- "自调用(this.method)为什么失效?"
- "异常被捕获后事务会怎样?"
第三层:原理分析
- "Spring AOP 代理是怎么实现事务的?"
- "为什么代理机制导致这些问题?"
第四层:解决方案
- "如何解决自调用问题?"
- "如何避免异常导致的失效?"
1.2 ❌ 错误示范
候选人原话 A:"只要标注了 @Transactional,事务就一定生效。"
问题诊断:
- 完全错误,没有任何实战经验
- 说明没有踩过事务失效的坑
- 完全没有理解代理机制
候选人原话 B:"private 方法不会生效,因为 Spring 代理不了 private 方法。"
问题诊断:
- 知道一个失效场景,但不知道为什么
- 不理解 CGLIB 代理的限制
候选人原话 C:"自调用可以注入自身 Bean 来解决。"
问题诊断:
- 知道解决方案,但说不清为什么
- 不理解 AOP 代理的原理
1.3 标准回答
P5 回答:失效场景概览
@Transactional 失效的常见场景:
1.4 追问升级
追问 1:为什么 private 方法不生效?
这是由 CGLIB 代理机制决定的:
Spring 的处理:
追问 2:自调用为什么失效?
这是事务失效最常见的原因:
原理图解:
正确做法:
或者:
追问 3:异常被捕获为什么不回滚?
Spring 的异常处理规则:
正确做法:
追问 4:其他失效场景详解
二、延伸问题 🟡
2.1 自调用问题的深层分析
2.2 代理对象的获取
exposeProxy = true 会有性能开销,Spring Boot 2.x 默认是 false。生产环境建议使用注入自身的方式,而不是 AopContext。
2.3 事务失效的排查方法
三、生产避坑
3.1 最常见的失效:自调用
3.2 异常处理的最佳实践
3.3 检查事务是否生效
四、工程选型
4.1 避免事务失效的设计原则
- 避免自调用:不同业务逻辑拆分到不同 Bean
- 使用 public 方法:
@Transactional只对 public 方法生效 - 正确处理异常:不要随意捕获异常后不抛出
- 避免在事务方法中调用远程服务:远程调用超时可能导致事务长时间占用
- 选择合适的传播行为:不要滥用 REQUIRES_NEW
4.2 事务失效场景速查表
五、面试总结
@Transactional 失效场景是 Spring 事务中最考察实战经验的知识点。
P5 候选人能说出 1-2 个失效场景(private 方法、自调用)。 P6 候选人能说出 4-5 个场景,能解释为什么 private 方法不生效,能说出自调用和异常处理的问题。 P7 候选人能说出所有常见场景,能画出完整的失效原因分析图,能给出实用的解决方案。
记住,事务失效不是背知识点,而是踩过坑之后的经验总结。