从另一个方法调用的@Transactional 方法没有获得事务

Posted

技术标签:

【中文标题】从另一个方法调用的@Transactional 方法没有获得事务【英文标题】:@Transactional method called from another method doesn't obtain a transaction 【发布时间】:2011-07-03 19:40:57 【问题描述】:

在 Spring 中,使用 @Transactional 注释的方法如果还没有新事务,则将获得新事务,但我注意到,如果从非事务性方法调用事务性方法,则不会获得任何事务.这是代码。

@Component
public class FooDao 
    private EntityManager entityManager;

    @PersistenceContext
    protected void setEntityManager(EntityManager entityManager) 
        this.entityManager = entityManager;
    

    @Transactional
    public Object save(Object bean) 
        return this.entityManager.merge(bean);
    

    public Object saveWrap(Object bean) 
        return save(bean);
    


@Component
public class FooService 
    private FooDao fooDao;

    public void save(Object bean) 
        this.fooDao.saveWrap(bean); // doesn't work.
        this.fooDao.save(bean); // works
    

saveWrap() 是调用save() 的常规方法,它是事务性的,但saveWrap() 不会保留任何更改。

我正在使用 Spring 3 和 Hibernate 3。我在这里做错了什么?谢谢。

【问题讨论】:

【参考方案1】:

这是 Springs AOP 的限制之一。因为dao bean在spring创建的时候实际上是一个代理,这意味着从同一个类中调用一个方法不会调用advice(也就是事务)。任何其他切入点也是如此

【讨论】:

用@Transactional 注释saveWrap 方法没有坏处。事务传播的默认行为是必需的,这意味着如果你要获得一个嵌套事务(即你在一个事务中,然后你调用另一个也是 @Transactional 的方法)将只是使用现有事务而不是创建如果那是您所害怕的,则另一种) 用cglib做代理怎么样?我记得 cglib 代理建议每个方法,即使你在同一个类中调用它。 @ClintonBosch 如果这个新的 Transactional 方法(通过 REQUIRED 传播从另一个 Transactional 方法调用)将传播设置为 REQUIRES_NEW 怎么办?我实际上正在查看一个代码库做这件事,我很好奇它是否仍将使用相同的事务或创建一个新事务。【参考方案2】:

是的,这是预期的行为。 @Transactional 告诉 spring 在对象周围创建一个代理。代理拦截来自其他对象的对该对象的调用。代理不会拦截对象内的调用。

如果您想完成这项工作,请在从“外部”调用的方法上添加@Transactional

【讨论】:

另一种选择是将整个类标记为事务性,方法是将@Transactional()(可能为 readOnly=true/false,propagation=something 等)放在类的顶部,然后覆盖 readOnly和/或根据需要每个方法的传播值。【参考方案3】:

我知道这有点晚了,但我想添加一个方法来克服这个限制,即在方法中从应用程序上下文中获取 spring bean 并调用该方法。当从应用程序上下文中获取 spring bean 时,它将是代理 bean 而不是原始 bean。由于代理 bean 现在调用的是方法而不是原始 bean,因此将在其上实现事务建议。

【讨论】:

【参考方案4】:

一种可能的解决方法是调用该方法,就像它是从“外部”调用一样

你可以通过获取组件的当前代理然后调用方法来做到这一点:

 ((MyService) AopContext.currentProxy()).innerMethod();

来源:https://www.programmersought.com/article/58773839126/

【讨论】:

以上是关于从另一个方法调用的@Transactional 方法没有获得事务的主要内容,如果未能解决你的问题,请参考以下文章

@Transactional 方法调用另一个没有@Transactional 注释的方法?

如何使用 React 和 Redux 从另一个组件访问 ref?

@transactional 回滚以后方法执行吗

@Transactional 注意事项方法调用

Spring 为在 @Transactional 注释方法中调用的每个 JpaRepository 方法打开一个新事务

Service调用其他Service的private方法, @Transactional会生效吗(上)