我们有:
@Transactional(propagation = Propagation.REQUIRED)
public class MyClass implementes MyInterface { ...
MyInterface 有一个方法:go()
。
当 go() 执行时,我们启动一个新事务,该事务在方法完成时提交/回滚 - 这很好。
现在假设在 go() 中,我们调用 MyClass 中的私有(private)方法,该方法具有 @Transactional(propagation = Propagation.REQUIRES_NEW
。似乎 Spring “忽略”了 REQUIRES_NEW 注释并且不启动新事务。我相信这是因为 Spring AOP 是在接口(interface)级别(MyInterface)操作的,不会拦截任何对 MyClass 方法的调用。这样对吗?
有没有办法在 go() 事务中启动一个新事务?是调用另一个将事务配置为 REQUIRES_NEW 的 Spring 托管 bean 的唯一方法吗?
更新:添加当客户端执行 go()
时,它们是通过对接口(interface)的引用而不是类来执行的:
@Autowired
MyInterface impl;
impl.go();
最佳答案
来自 Spring 引用 2.5:
When using proxies, the
@Transactional
annotation should only be applied to methods with public visibility. If you do annotate protected, private or package-visible methods with the@Transactional
annotation, no error will be raised, but the annotated method will not exhibit the configured transactional settings.
所以 Spring 会忽略非公共(public)方法上的 @Transactional
注释。
还有,
In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with
@Transactional
!
因此,即使您将方法设为 public
,从同一类的方法中调用它也不会启动新事务。
可以在事务设置中使用aspectj
模式,使事务相关的代码编织在类中,运行时不创建代理。
见 the reference document了解更多详情。
另一种可能的方法是在类本身中获取类的spring代理并在其上调用方法而不是this
:
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class SomeService {
@Autowired
private ApplicationContext applicationContext;
private SomeService getSpringProxy() {
return applicationContext.getBean(this.getClass());
}
private void doSomeAndThenMore() {
// instead of
// this.doSometingPublicly();
// do the following to run in transaction
getSpringProxy().doSometingPublicly();
}
public void doSometingPublicly() {
//do some transactional stuff here
}
}
关于java - 在 Spring bean 中启动新事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3037006/