在春豆中开始新交易

2022-08-31 20:01:28

我们有:

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

MyInterface 只有一个方法:.go()

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

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

有没有办法在go()交易中开始新的交易?调用另一个已将事务配置为REQUIRES_NEW的 Spring 受管 Bean 的唯一方法是什么?


更新:添加当客户端执行时,它们通过对接口而不是类的引用来执行此操作:go()

@Autowired
MyInterface impl;

impl.go();

答案 1

来自春季参考2.5:

使用代理时,注释应仅应用于具有公共可见性的方法。如果使用批注对受保护的、私有的或包可见的方法进行批注,则不会引发任何错误,但带批注的方法不会显示配置的事务设置。@Transactional@Transactional

因此,Spring忽略了对非公共方法的注释。@Transactional

在代理模式(这是默认设置)中,只有通过代理传入的“外部”方法调用才会被截获。这意味着“自调用”,即目标对象内的方法调用目标对象的其他方法,即使调用的方法标记为 !@Transactional

因此,即使您制作了方法,从同一类的方法中调用它也不会启动新事务。public

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

有关更多详细信息,请参阅参考文档

另一种可能的方法是在类本身中获取类的弹簧代理,并在其上调用方法,而不是: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
    }

}

答案 2

@Transactional只有当它是在方法上时才会被注意到,由于Spring AOP的工作方式。public

但是,如果需要,您可以以编程方式启动新事务,例如TransactionTemplate

TransactionTemplate txTemplate = new TransactionTemplate(txManager);                
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(status -> {
        // do stuff
});

推荐