Spring @Async生成LazyInitializationExceptions

时间:2013-06-24 14:47:18

标签: spring asynchronous lazy-initialization

Spring MVC应用程序需要执行一个需要几分钟的密集计算工作。客户端希望以异步方式运行此作业。但是在我对方法启用@Async注释后(参见代码1)并获得错误(参见代码2)。我的web.xml和web-appliaiton-context.xml也在下面给出。我试图找到解决方法来解决这个问题,但失败了。请帮忙。

代码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>

5 个答案:

答案 0 :(得分:7)

这里的问题是,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 :(得分:2)

你的@Async没有问题,这是由你的  您的实体类,当您将映射从一个声明为多个时,请尝试将fetchType指定为EAGER。有点像这样:

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

答案 2 :(得分:1)

您可以尝试以下

@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)

答案 3 :(得分:0)

你可以尝试

@Proxy (lazy = false)

在两个实体类之上。它适用于我的情况。

答案 4 :(得分:0)

在DAO类逻辑中使用Hibernate.initialize(obj)以避免延迟加载异常。