我有两个预定的任务,它们以不同的时间间隔运行。第一项任务计划每5秒运行一次,第二项任务计划每10分钟运行一次。
@EnableScheduling
public class ScheduledTask {
@Autowired
private taskService taskService;
@Scheduled(every 5 second)
public void scheduleTaskA() {
taskService.taskA()
}
@Scheduled(every 10 minute)
public void scheduleTaskB() {
taskService.taskB()
}
}
public class TaskServiceImpl implements TaskService {
@PersistenceContext
private EntityManager entityManager;
void taskA(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure1");
if(query.execute())
query.getSingleResult();
}
void taskB(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure2");
if(query.execute())
query.getSingleResult();
}
}
每次第二个任务运行时,它都会抛出java.lang.IllegalStateException: Session/EntityManager is closed
。看起来第一个任务是关闭entityManager。在不更改@PersistenceContext批注的情况下如何避免这种情况?
完整堆栈跟踪
java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:357) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:138) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.query.internal.AbstractProducedQuery.getMaxResults(AbstractProducedQuery.java:892) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.getResultList(ProcedureCallImpl.java:716) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.getSingleResult(ProcedureCallImpl.java:744) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at sun.reflect.GeneratedMethodAccessor150.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:374) ~[spring-orm-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at com.sun.proxy.$Proxy149.getSingleResult(Unknown Source) ~[na:na]
at com.test.service.TaskServiceImpl.taskA(TaskServiceImpl.java:602) ~[classes/:0.0.1-SNAPSHOT]
at com.test.service.TaskServiceImpl....(TaskServiceImpl.java:112) ~[classes/:0.0.1-SNAPSHOT]
at com.test.service.TaskServiceImpl....(TaskServiceImpl.java:163) ~[classes/:0.0.1-SNAPSHOT]
at com.test.schedule.ScheduledTask.scheduledTaskA(ScheduledTask.java:45) ~[classes/:0.0.1-SNAPSHOT]
at sun.reflect.GeneratedMethodAccessor143.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_171]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
答案 0 :(得分:1)
我非常确定您需要在事务上下文中运行StoredProcedureQuery。请尝试在每个方法中添加@Transactional。
@Transactional
void taskA(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure1");
if(query.execute())
query.getSingleResult();
}
@Transactional
void taskB(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure2");
if(query.execute())
query.getSingleResult();
}
您可能还希望将传播设置为new,以确保它们在各自独立的事务@Tansacational(propagation = Propagation.REQUIRES_NEW)中运行。
答案 1 :(得分:0)
由于尝试共享同一个实体管理器,因此出现错误。这是短暂的对象。
您可以应用以下两种解决方案:
1)注入EntityManagerFactory并在EntityManager内部,在方法中使用factory创建EntityManager。
@PersistenceUnit(unitName= "em")
private EntityManagerFactory emf;
2)创建两个不同的服务,让每个服务都有自己的实体管理器实例。 (不确定由调度程序调用方法时第二次是否可以工作。进行测试并让我知道。)