如何重构@Transactional方法来拆分非事务性部分

Mic*_*urd 6 java hibernate transactions spring-annotations hibernate-annotations

我有一个数据访问类,它作为独立的Java应用程序的一部分运行.它目前正在工作,这意味着定义了一个事务管理器,但我想重构该类以减少事务的范围,但如果我这样做,我得到org.hibernate.HibernateException:没有Hibernate Session绑定到线程,并且配置不允许在这里创建非事务性的,这意味着移动@Transactional会以某种方式阻止它被识别.

我的原始版本的重构方法是私有的,但我发现建议将其更改为public,因为在某些情况下注释不会被选中.

public class DoStuff {
    @Transactional
    public void originalMethod() {
        // do database stuff
        ...

        // do non-database stuff that is time consuming
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是重构以下内容

public class DoStuff {
    public void originalMethod() {
        doDatabaseStuff()

        doNonDatabaseStuff()
    }

    @Transactional
    public void doDatabaseStuff() {
        ...
    }

    public void doNonDatabaseStuff() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

gre*_*ude 7

编辑:

您需要了解Spring代理如何工作以理解为什么您的重构不起作用.

对象引用的方法调用将是代理上的调用,因此代理将能够委托给与该特定方法调用相关的所有拦截器(通知).但是,一旦调用最终到达目标对象,就会调用它可能对其自身进行的任何方法调用,而不是针对此引用调用,而不是代理.这具有重要意义.这意味着自我调用不会导致与方法调用相关的建议有机会执行.

@Transactional使用Spring AOP,Spring使用代理.这意味着当您从另一个类调用@Transactional方法时,Spring将使用代理,因此将应用事务建议.但是,如果从同一个类调用该方法,则spring将使用"this"引用而不是代理,因此不会应用事务性建议.

原答案:

在类似的情况下,这对我有用.

public class DoStuff implement ApplicationContextAware {    
private ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
    CONTEXT = context;
}

    public void originalMethod() {           
        getSpringProxy().doDatabaseStuff()              
        doNonDatabaseStuff()       
    }

    private DoStuff getSpringProxy() {
        return context.getBean(this.getClass());     
    } 
    @Transactional       
    public void doDatabaseStuff() {           
        ...       
    }          

    public void doNonDatabaseStuff() {           
        ...       
    }   
} 
Run Code Online (Sandbox Code Playgroud)

说明:

  1. 创建类ApplicationContextAware,因此它具有对上下文的引用
  2. 当您需要调用事务方法时,从上下文中获取实际的spring代理
  3. 使用此代理调用您的方法,以便实际应用@Transactional.