这是一个非常常见的关于 Spring 事务传播机制 的问题,核心问题是:
在同一个类中,方法 A 调用方法 B,而方法 B 上有
@Transactional
注解。当调用方法 A 时,如果发生异常,方法 B 的事务会生效吗?
@Service
public class MyService {
public void methodA() {
// 做一些操作
methodB(); // 内部调用methodB
}
@Transactional
public void methodB() {
// 数据库操作
}
}
因为 Spring 的事务是通过 动态代理(JDK Proxy 或 CGLIB) 实现的:
把 methodB()
放到另一个 Service 类中:
@Service
public class MyService {
@Autowired
private AnotherService anotherService;
public void methodA() {
// 做一些操作
anotherService.methodB(); // 外部调用
}
}
@Service
public class AnotherService {
@Transactional
public void methodB() {
// 数据库操作
}
}
✅ 这样事务就会生效了。
AopContext.currentProxy()
获取代理对象(慎用)你可以通过以下方式获取当前类的代理对象来调用 methodB()
:
@Service
public class MyService implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Transactional
public void methodB() {
// 数据库操作
}
public void methodA() {
// 获取当前类的代理对象
MyService proxy = (MyService) AopContext.currentProxy();
proxy.methodB(); // 使用代理调用
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
applicationContext = ctx;
}
}
⚠️ 注意事项:
如果你希望方法B的行为能被方法A控制,可以指定事务传播行为,例如:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 总是开启一个新事务
}
场景 | 事务是否生效 | 说明 |
---|---|---|
同一类内调用带 @Transactional 的方法 |
❌ 不生效 | Spring 无法拦截内部方法调用 |
不同类之间调用带 @Transactional 的方法 |
✅ 生效 | 通过代理对象调用,事务生效 |
使用 AopContext.currentProxy() 调用 |
✅ 可以生效 | 需要设置 expose-proxy=true |