在Spring bean中启动新的事务

我们有:

@Transactional(propagation = Propagation.REQUIRED) public class MyClass implementes MyInterface { ... 

MyInterface有一个方法: go()

当go()执行时,我们开始一个新的事务,当方法完成时提交/回滚 – 这很好。

现在让我们在go()中调用MyClass中的一个私有方法,该方法具有@Transactional(propagation = Propagation.REQUIRES_NEW Spring似乎忽略了REQUIRES_NEW注释并且不启动一个新的事务,我相信这是因为Spring AOP在接口级别(MyInterface)上运行,不会拦截任何对MyClass方法的调用,这是正确的吗?

有没有办法在go()事务中启动一个新的事务? 是唯一的方法来调用另一个被configuration为REQUIRES_NEW事务的Spring托pipebean?


更新 :添加,当客户端执行go()他们通过接口的引用,而不是类:

 @Autowired MyInterface impl; impl.go(); 

从Spring参考2.5:

使用代理时,@ @Transactional注释只能应用于具有公开可见性的方法。 如果使用@Transactional注释标注protected,private或package-visible方法,则不会引发错误,但注释的方法不会显示已configuration的事务设置。

所以Spring忽略了非公有方法的@Transactional注解。

也,

在代理模式下(这是默认的),只有通过代理进入的“外部”方法调用才会被拦截。 这意味着即使被调用的方法标记为@Transactional ,“自调用”(即调用目标对象的其他方法的目标对象内的方法)也不会导致实际的事务处理。

所以即使你public你的方法,在同一个类的方法中调用它也不会启动一个新的事务。

您可以在事务设置中使用aspectj模式,以便在类中编写事务相关的代码,并且在运行时不会创build代理。

请参阅参考文件了解更多详情。

这样做的另一种可能的方式是在类中获取类的spring代理,并调用它的方法而不是:

 @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 } } 

由于Spring AOP的工作原理,@ @Transactional只会在public方法中被注意到。

但是,如果需要,可以使用TransactionTemplate 编程方式启动新的 TransactionTemplate ,例如

 TransactionTemplate txTemplate = new TransactionTemplate(txManager); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); txTemplate.execute(new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus status) { // do stuff } }); 

总之,您必须通过代理来调用方法来实现事务行为。 问题中提到,可以在同一个bean中调用“REQUIRES_NEW”。 要做到这一点,你必须做一个“自我”的参考。 在spring它不是简单可能的。 你必须注入@Resource注解。

 @Service("someService") public class ServieImpl implements Service { @Resource(name = "someService") Service selfReference; @Transactional public void firstMethod() { selfReference.secondMethod(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void secondMethod() { //do in new transaction } } 

调用inf firstMethod调用代理,而不是“this”,这将使“REQUIRES_NEW”事务工作。