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>
答案 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)
以避免延迟加载异常。