在 Spring bean 中启动新事务 [英] Starting new transaction in Spring bean

查看:13
本文介绍了在 Spring bean 中启动新事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有:

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

MyInterface 有一个方法:go().

MyInterface has a single method: go().

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

When go() executes we start a new transaction which commits/rollbacks when the method is complete - this is fine.

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

Now let's say in go() we call a private method in MyClass that has @Transactional(propagation = Propagation.REQUIRES_NEW. It seems that Spring "ignores" the REQUIRES_NEW annotation and does not start a new transaction. I believe this is because Spring AOP operates on the interface level (MyInterface) and does not intercept any calls to MyClass methods. Is this correct?

有没有办法在 go() 事务中开始一个新的事务?是调用另一个将事务配置为 REQUIRES_NEW 的 Spring 托管 bean 的唯一方法吗?

Is there any way to start a new transaction within the go() transaction? Is the only way to call another Spring managed bean that has transactions configured as REQUIRES_NEW?

更新:补充一点,当客户端执行 go() 时,它们是通过对接口的引用而不是类来执行的:

Update: Adding that when clients execute go() they do so via a reference to the interface, not the class:

@Autowired
MyInterface impl;

impl.go();

推荐答案

来自 Spring 参考 2.5:

From the Spring reference 2.5:

使用代理时,@Transactional 注释应该只应用于公开可见的方法.如果你注释了 protected、private 或带有 @Transactional 注释的包可见方法,不会出错被引发,但带注释的方法不会显示配置的事务性设置.

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 忽略了非公共方法上的 @Transactional 注释.

So Spring ignores @Transactional annotation on non-public methods.

还有,

在代理模式下(默认),只有外部"方法调用进来通过代理会被拦截.这意味着自我调用",即目标对象中的一个方法调用目标的其他方法对象,即使被调用,也不会在运行时导致实际事务方法标记为 @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,从同一类的方法中调用它也不会启动新事务.

So even if you make your method public, calling it from within a method of same class will not start a new transaction.

可以在事务设置中使用aspectj模式,这样事务相关的代码就编织在类中,运行时不创建代理.

You can use aspectj mode in transaction settings so that the transaction related code is weaved in the class and no proxy is created at runtime.

请参阅参考文档 了解更多详情.

See the reference document for more details.

另一种可能的方法是在类本身中获取类的 spring 代理并调用它的方法而不是this:

Another possible way of doing this is fetching the spring proxy of the class in the class itself and call methods on it rather than 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
    }

}

这篇关于在 Spring bean 中启动新事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆