Spring Boot 事务失效场景
→ 返回 面试 · 速查全集 SpringBoot常见面试题
@Transactional 基于 Spring AOP 代理;以下场景事务不生效或不符合预期。完整传播行为见 事务管理。
速查表
| # | 场景 | 原因 | 解决 |
|---|---|---|---|
| 1 | 同类内部自调用 | 绕过代理,AOP 不拦截 | 注入自身代理、拆 Bean、AopContext.currentProxy() |
| 2 | 方法 非 public | 默认只代理 public | 改为 public 或 AspectJ 织入 |
| 3 | 异常被 catch 未抛出 | 代理认为方法成功 | 重新抛出或 setRollbackOnly() |
| 4 | 受检异常默认不回滚 | 默认只回滚 RuntimeException | rollbackFor = Exception.class |
| 5 | 类未被 Spring 管理 | 无代理对象 | @Service / @Component |
| 6 | 数据库/引擎不支持 | MyISAM 等 | 改用 InnoDB |
| 7 | 多数据源未指定 | 事务绑错 Connection | @Transactional + 正确 TransactionManager |
1. 同类内部调用(最高频)
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
orderRepo.save(order);
sendNotification(order); // ❌ 直接调用,不走代理
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendNotification(Order order) { /* ... */ }
}正确做法:
@Autowired
private OrderService self; // 注入的是代理
public void createOrder(Order order) {
orderRepo.save(order);
self.sendNotification(order); // ✅
}或拆到 NotificationService 独立 Bean。
2. 方法非 public
@Transactional
protected void update() { } // ❌ 无效3. 异常被吞
@Transactional
public void process() {
try {
risky();
} catch (Exception e) {
log.error("fail", e); // ❌ 未抛出,不回滚
}
}4. 受检异常不回滚
@Transactional // 默认不回滚 IOException
public void export() throws IOException { ... }
@Transactional(rollbackFor = Exception.class) // ✅
public void export() throws IOException { ... }面试一句话
事务本质是 代理对象 在方法前后操作 Connection;任何绕过代理或让代理以为成功的写法都会失效。