|
@Transactional 注解在 Spring 中用于声明式事务管理,但在某些场景下会失效。
1、方法非 public 修饰
- 原因:Spring AOP 代理(CGLIB/JDK 动态代理)无法拦截 private/protected 的方法。
- 解决:确保事务方法为 public。
// ✅ 正确
@Transactional
public void createUser() { ... }
// ❌ 失效
@Transactional
private void createUser() { ... }
2、自调用问题(同类内调用)
- 原因:类内部方法调用(如 A.a() 调用 A.b())会绕过代理对象,导致 @Transactional 失效。
- 解决:
① 注入自身代理对象:@Autowired private MyService self; 后调用 self.b()。
② 通过 AopContext 获取代理:((MyService) AopContext.currentProxy()).b()(需开启 @EnableAspectJAutoProxy(exposeProxy = true))。我更喜欢把逻辑写到另一个类中,然后再进行调用。
@Service
public class UserService {
@Autowired
private UserService self; // 注入自身代理
public void methodA() {
// ❌ 直接调用失效
// methodB();
// ✅ 通过代理调用生效
self.methodB();
}
@Transactional
public void methodB() { ... }
}
3、异常类型未被捕获
① 默认只捕获 RuntimeException 和 Error。
② 若抛出 IOException 等受检异常,事务不会回滚。
③ 若异常被 catch 后未重新抛出,事务失效。
① 使用 rollbackFor 指定异常类型:@Transactional(rollbackFor = Exception.class)
② 避免在方法内吞没异常。
// ✅ 回滚受检异常
@Transactional(rollbackFor = Exception.class)
public void update() throws IOException {
try {
// 数据库操作
} catch (Exception e) {
// ❌ 错误:吞没异常
// log.error(e);
// ✅ 正确:重新抛出
throw new BusinessException(e);
}
}
4、数据库引擎不支持事务
5、事务传播行为配置不当
// ❌ 内层方法挂起事务
@Transactional(propagation = Propagation.NEVER)
public void innerMethod() { ... }
6、多线程调用(异步调用)
7、非 Spring 管理的 Bean
8、方法 final 或 static
9、未启用事务管理
10、非事务性方法调用
这些都是 @Transactional 可能失效的常见原因。如果遇到事务失效的问题,可以逐一排查这些情况。在工作中,有时出现了数据不一致的情况,去排查才发现是事务失效了。
知是行之始,行是知之成。-- 烟沙九洲
来源:https://www.cnblogs.com/yanshajiuzhou/p/18922768 |