我们有:
@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()事务中启动新事务?是否只能调用另一个另一个 Spring托管bean,其事务配置为REQUIRES_NEW?
更新:当客户端执行go()
时,通过对接口的引用而不是类来添加:
@Autowired
MyInterface impl;
impl.go();
答案 0 :(得分:73)
从Spring参考2.5:
使用代理时,
@Transactional
注释应仅应用于 公众可见度的方法。如果您注释protected,private或 包含@Transactional
注释的包可见方法,没有错误 引发,但带注释的方法不会显示已配置的事务 设置。
因此Spring忽略了对非公共方法的@Transactional
注释。
此外,
在代理模式(默认设置)下,只有“外部”方法调用进入 通过代理将被截获。这意味着'自我调用', 即目标对象内调用目标的其他方法的方法 对象,即使被调用也不会在运行时导致实际的事务 方法标有
@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
}
}
答案 1 :(得分:42)
@Transactional
只会在public
方法上被注意到。
但是,如果您愿意,可以TransactionTemplate
使用TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
// do stuff
}
});
,例如
{{1}}
答案 2 :(得分:5)
简而言之,您必须通过代理调用方法来实现事务行为。 可以在问题中询问的同一个bean中调用“REQUIRES_NEW”。要做到这一点,你必须做一个“自我”的参考。 在春天,它不是直截了当的。你必须注射它 使用@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
}
}
firstMethod中的调用调用代理而不是“this”,这将使“REQUIRES_NEW”事务起作用。