更多内容欢迎关注我(持续更新中,欢迎Star✨)
Github:CodeZeng1998/Java-Developer-Work-Note
(技术)微信公众号:CodeZeng1998
(生活)微信公众号:好锅
其他平台:CodeZeng1998、好锅
Spring 中事务失效的场景有哪些?
- 非公共方法上使用
@Transactional
- 自调用(同一类内部方法调用)
@Transactional
注解的传播行为设置不当- 异常不在被捕获范围或异常未抛出
- 多线程场景
- 代理模式选择不当
- 事务管理器配置不正确
- 使用
final
方法
在Spring中,使用@Transactional
注解进行声明式事务管理时,可能会出现事务失效的情况。常见的事务失效场景如下:
1. 非公共方法上使用@Transactional
Spring的AOP机制默认只会拦截公共(public
)方法。因此,如果你在非公共方法(如private
、protected
或package-private
)上使用@Transactional
,事务将不会生效。
示例:
@Transactional
private void privateMethod() {
// 事务不会生效
}
2. 自调用(同一类内部方法调用)
如果一个类的方法在调用同类的另一个标记了@Transactional
的方法时,由于Spring AOP是基于代理实现的,内部调用不会经过代理对象,因此事务不会生效。
原因: Spring AOP的事务管理是基于代理模式实现的。当你在一个类中调用同一个类中的另一个方法时,如果这个被调用的方法上有@Transactional
注解,事务不会生效。这是因为自调用是直接通过this
调用的,而不是通过代理对象调用的,因此不会触发AOP切面。
原理: Spring使用代理对象来管理事务。当你调用一个带有@Transactional
的方法时,实际上是通过代理对象来执行该方法的,代理对象会负责处理事务逻辑(如开启、提交、回滚事务等)。但是,当同一类内部方法调用时,this
引用是当前对象的实际实例,而不是代理对象,因此不会触发事务。
示例代码:
@Service
public class MyService {
@Transactional
public void methodA() {
methodB(); // 直接调用,事务不会生效
}
@Transactional
public void methodB() {
// 事务代码
}
}
解决方案:
- 将方法拆分到不同的类中:将
methodB()
方法放到另一个@Service
类中,通过注入该类来调用。 - 通过代理对象调用:使用
ApplicationContext
或AopContext
获取代理对象,使用代理对象进行方法调用。
通过代理对象调用示例:
@Service
public class MyService {
@Autowired
private MyService selfProxy;
@Transactional
public void methodA() {
selfProxy.methodB(); // 使用代理对象调用,事务生效
}
@Transactional
public void methodB() {
// 事务代码
}
}