Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何重构@Transactional方法以拆分非事务性部分_Java_Hibernate_Transactions_Hibernate Annotations_Spring Annotations - Fatal编程技术网

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

Java 如何重构@Transactional方法以拆分非事务性部分,java,hibernate,transactions,hibernate-annotations,spring-annotations,Java,Hibernate,Transactions,Hibernate Annotations,Spring Annotations,我有一个数据访问类,它作为独立java应用程序的一部分运行。它目前正在工作,这意味着定义了一个事务管理器,但我想重构该类以减少事务的范围,但如果我这样做,我会得到org.hibernate.hibernate异常:没有绑定到线程的hibernate会话,配置不允许在此处创建非事务性的,这意味着移动@transactional会以某种方式阻止它被识别 我的原始版本中,重构方法是私有的,但我发现了一个将其更改为公共的建议,因为在某些情况下,注释不会被拾取 public class DoStuff {

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

我的原始版本中,重构方法是私有的,但我发现了一个将其更改为公共的建议,因为在某些情况下,注释不会被拾取

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

        // do non-database stuff that is time consuming
        ...
    }
}
我想做的是重构到以下内容

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

        doNonDatabaseStuff()
    }

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

    public void doNonDatabaseStuff() {
        ...
    }
}
编辑:

您需要理解重构无法工作的原因

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

@事务性使用SpringAOP,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() {           
        ...       
    }   
} 
说明:

  • 使类
    ApplicationContextAware
    ,使其具有对上下文的引用
  • 当需要调用事务性方法时,从上下文中获取实际的spring代理
  • 使用此代理调用您的方法,以便实际应用@Transactional

  • 您的方法看起来应该可以很好地工作,我希望这个问题与Spring代理有关

    我询问接口的原因与Spring应用事务行为的默认方法——JDK动态代理有关

    如果类的实际定义是:

    public class DoStuff implements Doable {
      public void originalMethod() {
    
      }
    }
    
    public interface Doable {
      public void originalMethod();
    }
    
    如果这确实是结构,那么当您移动到新结构时,Spring无法代理新的
    doDatabaseStuff
    方法

    修复此问题的选项:

    • 将新方法添加到接口中,以确保Spring可以代理它们
    • 转向使用基于CGLIB的代理(这些代理不依赖于接口)

    您的交易经理在哪里?您可以添加更多详细信息吗?您的类DoStuff实现了任何接口吗?没有接口,并且事务管理器是为原始类定义的。没有,该类是一个POJO,没有在所有位置实现的接口。还是。这都是真的:)我不是不同意(我只是说它不适用于本例:-)原始类已经识别@Transactional并正确工作。它只有在重构后才会停止工作。这似乎是我的问题。谢谢