2013-06-24 85 views
0

Spring MVC應用程序需要執行需要幾分鐘的密集計算作業。客戶希望以異步方式運行此作業。但是,在方法上啓用@Async註釋(請參閱代碼1)並獲取錯誤(請參閱代碼2)之後。我的web.xml和web-appliaiton-context.xml也在下面介紹。我試圖找到一個解決方法來解決這個問題,但失敗了。請幫忙。Spring @Async生成LazyInitializationExceptions

代碼1:

@Service 
public class AsyncServiceImpl implements AsyncServiceInt{ 

    protected int pertArrSize = 1000; 
    @Autowired 
    protected TblvDao tblvDao1 = null; 

    @Override 
    @Async 
    public void startSlowProcess(Integer scenarioId) throws SecurityException, IllegalArgumentException, IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 
     batchUpdateSummaryPertSim(scenarioId); 

    } 

    public void batchUpdateSummaryPertSim(Integer scenarioId) throws SecurityException, IllegalArgumentException, IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException 
    { 
     double[] summaryArry = new double[pertArrSize]; 
     summaryArry = summaryPertSim_env(scenarioId, summaryArry); 
    } 

    @Transactional 
    private double[] summaryPertSim_env(Integer scenarioId, 
    double[] summaryArry) throws IOException, ClassNotFoundException, SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException { 
     ScenarioTblv scenario = tblvDao1.getScenarioTblv(scenarioId); 
     TblvResultSaved savedResult = scenario.getTblvResultSaved(); 
     TblvScenarioCategory4 tblvScenarioCategory4 = new TblvScenarioCategory4(); 
     List<TblvScenarioCategory4> tblvScenarioCategory4List = scenario 
     .getTblvScenarioCategory4List(); 
     Double min = 0.0, max = 0.0, ml = 0.0; 
     Integer conf = 4; 
     if (savedResult.getEnvDist() != null) { 

      byte[] st = (byte[]) savedResult.getEnvDist(); 
      ByteArrayInputStream baip = new ByteArrayInputStream(st); 
      ObjectInputStream ois = new ObjectInputStream(baip); 

      summaryArry = (double[]) ois.readObject(); 
      } else { 
      for (int i = 0; i < tblvScenarioCategory4List.size(); i++) { 
       tblvScenarioCategory4 = tblvScenarioCategory4List.get(i); 

       vTblvScenarioEffectChoose v = tblvDao1 
       .getvTblvScenarioEffectChooseById(tblvScenarioCategory4 
       .getId()); 

       if (v.getC1id() == 1) { 
        tblvScenarioCategory4.setImpactYearlyUnitsSim(pertArrSize); 
        min = tblvScenarioCategory4 
        .getTblvEffectScenarioImpactUnitValue() 
        .getLowValue(); 
        max = tblvScenarioCategory4 
        .getTblvEffectScenarioImpactUnitValue() 
        .getHighValue(); 
        ml = tblvScenarioCategory4 
        .getTblvEffectScenarioImpactUnitValue() 
        .getMostValue(); 
        conf = tblvScenarioCategory4 
        .getTblvEffectScenarioImpactUnitValue().getConf(); 
        if ((conf == null) || (conf == 0)) 
        conf = 4; 

        double[] MOPertArr; 

        MOPertArr = getPertArry(min, max, ml, conf, pertArrSize); 

        double[] benefitResult = new double[pertArrSize]; 

        for (int j = 0; j < pertArrSize; j++) { 
         tblvScenarioCategory4.setSimIndex(j); 
         tblvScenarioCategory4 
         .getTblvEffectScenarioImpactUnitValue() 
         .setHighValue(MOPertArr[j]); 
         benefitResult[j] = tblvScenarioCategory4.getHighPvSum(); 
         summaryArry[j] = summaryArry[j] + benefitResult[j]; 
        } 
        tblvScenarioCategory4 
        .getTblvEffectScenarioImpactUnitValue() 
        .setHighValue(max); 
       } 

      } 
      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      ObjectOutputStream oos = new ObjectOutputStream(baos); 
      oos.writeObject(summaryArry); 
      byte[] summaryArryAsBytes = baos.toByteArray(); 
      savedResult.setEnvDist(summaryArryAsBytes); 
      tblvDao1.saveTblvResultSaved(savedResult); 
     } 
     return summaryArry; 
    } 

代碼2:

10:26:06,233 ERROR org.hibernate.LazyInitializationException:42 - failed to lazily initialize a collection of role: com.pb.prism.model.db.ScenarioTblv.tblvScenarioCategory4List, no session or session was closed 
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.pb.prism.model.db.ScenarioTblv.tblvScenarioCategory4List, no session or session was closed 
     at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) 
     at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) 
     at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119) 
     at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248) 
     at com.pb.prism.util.AsyncServiceImpl.summaryPertSim_env(AsyncServiceImpl.java:446) 
     at com.pb.prism.util.AsyncServiceImpl.batchUpdateSummaryPertSim(AsyncServiceImpl.java:41) 
     at com.pb.prism.util.AsyncServiceImpl.startSlowProcess(AsyncServiceImpl.java:34) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
     at java.lang.reflect.Method.invoke(Unknown Source) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
     at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:80) 
     at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) 
     at java.util.concurrent.FutureTask.run(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
     at java.lang.Thread.run(Unknown Source) 

Web.xml中

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> 


    <context-param> 
     <param-name>log4jConfigLocation</param-name> 
     <param-value>/WEB-INF/log4j.properties</param-value> 
    </context-param> 
    <listener> 
     <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> 
    </listener> 
    <listener> 
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 
    <listener> 
     <listener-class>com.pb.prism.listener.MTAServletContextListener</listener-class> 
    </listener> 
    <context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/spring/web-application-context.xml</param-value> 
    </context-param> 
    <filter> 
     <filter-name>openEntityManagerInViewFilter</filter-name> 
     <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>openEntityManagerInViewFilter</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    <!-- Enables Spring Security --> 
    <filter> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    <filter> 
     <filter-name>encoding-filter</filter-name> 
     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
     <init-param> 
     <param-name>encoding</param-name> 
     <param-value>UTF-8</param-value> 
     </init-param> 
    </filter> 
    <filter-mapping> 
     <filter-name>encoding-filter</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    <filter> 
     <filter-name>UrlRewriteFilter</filter-name> 
     <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>UrlRewriteFilter</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    <!-- Handles all requests into the application --> 
    <filter> 
     <filter-name>OpenSessionInViewFilter</filter-name> 
     <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>OpenSessionInViewFilter</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    <servlet> 
     <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> 
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
     <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value /> 
     </init-param> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
     <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> 
     <url-pattern>/app/*</url-pattern> 
    </servlet-mapping> 
</web-app> 

網絡appliation-context.xml中

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:task="http://www.springframework.org/schema/task" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans.xsd 
         http://www.springframework.org/schema/task 
         http://www.springframework.org/schema/task/spring-task-3.0.xsd 
         http://www.springframework.org/schema/context 
         http://www.springframework.org/schema/context/spring-context.xsd"> 

    <context:component-scan base-package="com.pb.prism" /> 

    <!-- Imports the configurations of the different infrastructure systems of the application --> 
    <import resource="data-access-context.xml" /> 
    <import resource="security-context.xml" /> 
    <import resource="webmvc-context.xml" /> 

    <bean id="applicationContextProvider" class="com.pb.prism.context.ApplicationContextProvider"></bean> 

    <!-- Configure the multipart resolver --> 
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
     <!-- one of the properties available; the maximum file size in bytes --> 
     <property name="maxUploadSize" value="2000000"/> 
    </bean> 


     <task:annotation-driven executor="myExecutor" />  
     <task:executor id="myExecutor" pool-size="5"/> 
</beans> 

回答

6

這裏的問題就是,Spring的AOP代理不延長而是換你的服務實例攔截來電。這樣做的結果是,在您的服務實例中對「this」的任何調用都將直接在該實例上調用,並且不會被包裝代理攔截(代理甚至不知道任何此類調用)。 (如Spring @Transaction method call by the method within the same class, does not work?中所述)

一個可能的解決方案是從服務中提取事務代碼,並將其置於一個單獨的類中。這樣,可以攔截對交易方法的調用,並且可以進行交易。

例如,

@Service 
public class AsyncServiceImpl implements AsyncServiceInt{ 

@Autowired private SlowProcess slowProcess; 

@Override 
@Async 
public void startSlowProcess(Integer scenarioId) { 
    slowProcess.execute(param); 
} 

.. 

public class SlowProcess { 

    @Transactional 
    public double[] execute() { .. } 

} 
+1

我將事務代碼提取到另一個單獨的類。有用。 – Alex

2

您的@Async沒有問題,這是由於您的實體類,當您聲明從一個映射到多個映射時,請嘗試將fetchType指定爲EAGER。有些事情是這樣的:

@OneToMany(fetch=FetchType.EAGER) 
public Collection<Role> getRoleSet(){ 
... 
} 
0

您可以嘗試

@Proxy (lazy = false) 

在兩個實體類的頂部。它適用於我的情況。

0

你可以嘗試以下

@Async 
@Transactional(propagation = Propagation.REQUIRES_NEW) 
0

使用Hibernate.initialize(obj)在DAO類的邏輯,以避免延遲加載異常。