一、一句话结论(面试开场必说 ⭐⭐⭐⭐⭐)
@Transactional 本质是 Spring AOP 动态代理,只要事务方法没有被 Spring 代理调用,就会失效。
二、@Transactional 失效的 10 大场景(重点 ⚠️)
✅ 1️⃣ 同类方法调用(最常见 ❌)
@Service
public class UserService {
public void outer() {
inner(); // ❌ 事务失效
}
@Transactional
public void inner() {}
}
❌ 原因
• 调用的是 this.inner()
• 绕过了 Spring 代理
✅ 解决
• 拆到另一个 Service
• 或通过代理对象调用
✅ 2️⃣ 方法是 private(❌ 直接失效)
@Transactional
private void save() {}
❌ 原因
• Spring AOP 是基于代理实现的,private 方法无法被代理类重写或拦截,因此不能被增强。
✅ 正确写法
@Transactional
public void save() {}
✅ 3️⃣ 方法是 final / static(❌)
@Transactional
public final void save() {}
❌ 原因
• CGLIB 无法重写 final 方法
• static 不属于对象
✅ 4️⃣ 异常被 catch 吃掉(❌)
@Transactional
public void save() {
try {
int i = 1 / 0;
} catch (Exception e) {
// ❌ 不抛异常 = 不回滚
}
}
✅ 正确
catch (Exception e) {
throw e;
}
✅ 5️⃣ 抛出的异常不是 RuntimeException(❌)
@Transactional
public void save() throws Exception {
throw new Exception(); // ❌ 默认不回滚
}
✅ 解决
@Transactional(rollbackFor = Exception.class)
✅ 6️⃣ 传播行为设置错误(❌)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void save() {}
❌ 原因
• 非事务方式执行
✅ 7️⃣ 数据库引擎不支持事务(❌)
数据库 引擎
MySQL ❌ MyISAM
MySQL ✅ InnoDB
📌 MyISAM 不支持事务
✅ 8️⃣ 未开启事务注解(❌)
// ❌ 忘了加
@EnableTransactionManagement
或 Spring Boot 未引入:
spring-tx
✅ 9️⃣ 多线程调用(❌)
@Transactional
public void parent() {
new Thread(() -> child()).start();
}
❌ 原因
• Spring 事务 绑定线程
• 子线程无事务
✅ 🔟 非 Spring 管理的 Bean(❌)
new UserService().save(); // ❌ 不在容器中
✅ 必须是:
@Autowired
UserService userService;
三、一张表彻底记住(面试救命表 ⭐⭐⭐⭐⭐)
| 场景 | 是否失效 |
|---|---|
| 同类方法调用 | ❌ |
| private 方法 | ❌ |
| final 方法 | ❌ |
| 异常被 catch | ❌ |
| 非 RuntimeException | ❌ |
| NOT_SUPPORTED | ❌ |
| MyISAM | ❌ |
| 多线程 | ❌ |
| 非 Spring Bean | ❌ |
四、面试标准回答(背这段 ✅)
@Transactional 失效主要是因为 Spring 事务基于 AOP 动态代理,常见场景包括:同类方法调用、private/final 方法、异常被捕获、异常类型不匹配、传播行为错误、数据库不支持事务、多线程调用以及 Bean 未被 Spring 管理。
五、如何快速排查事务是否生效?
✅ 1️⃣ 看日志
Creating new transaction with name ...
✅ 2️⃣ 强制异常测试
throw new RuntimeException("test");
✅ 3️⃣ 打印代理对象
System.out.println(AopContext.currentProxy());
六、最佳实践(强烈建议 ✅)
✅ 事务方法 public
✅ 不在同类中调用
✅ 明确 rollbackFor = Exception.class
✅ 不吞异常
✅ 不使用 MyISAM
✅ 不在新线程中操作事务