冲突的春季计划

时间:2018-12-09 13:54:09

标签: java spring hibernate spring-boot spring-data

我有两个预定的任务,它们以不同的时间间隔运行。第一项任务计划每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]

2 个答案:

答案 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)创建两个不同的服务,让每个服务都有自己的实体管理器实例。   (不确定由调度程序调用方法时第二次是否可以工作。进行测试并让我知道。)