Spring Boot在关闭时关闭hibernate会话 - 在@Async方法完成之前

时间:2017-09-05 08:36:42

标签: java spring asynchronous spring-boot spring-data-jpa

我遇到一个Spring启动应用程序的问题,它在@Async任务(使用EntityManager)完成之前关闭了EntityManager /会话。

有两个与此问题相关的课程:

计划

预定方法会保留有限数量的作业,并在执行实际工作的@Async上调用XYJobProcessor方法。

@Component
public class XYJobProcessingTimer {

    private final XYJobService      xyJobService;
    private final XYJobProcessor    xyJobProcessor;

    //constructor skipped

    @Scheduled(initialDelayString = "${initial_delay}", fixedDelayString = "${delay}")
    public void performXYJobProcessing() {
        final String ticket = UUID.randomUUID().toString();
        final int reservedJobs = xyJobService.findAndReserveReadyXYJobs(ticket);

        if (reservedJobs > 0) {
            final Collection<XYJob> xyJobs = xyJobService.readReservedJobs(ticket);
            xyJobProcessor.process(xyJobs);
        }
    }

}

异步处理器

@Async带注释的方法调用访问EntityManager的服务。

@Service
public class XYJobProcessor {

    private final XYJobService  xyJobService;

    // constructor skipped

    @Async("xyJobProcessorExecutor")
    public void process(final Collection<XYJob> jobs) {
        // This service uses the EntityManager and takes some time depending o job count.
        xyJobService.createXYJobsAndDelete(jobs);
    }

}

配置

运行Executor任务的@Async的配置。创建的Threads是非守护进程。

@Configuration
public class AsyncExecutorConfiguration {

    @Bean(name = "xyJobProcessorExecutor")
    public Executor xyJobProcessorExecutor() {
        final SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
        executor.setConcurrencyLimit(10);
        executor.setThreadNamePrefix("Hasselhoff-");
        return executor;
    }

}

问题

当我关闭应用程序时,spring会立即关闭EntityManager会话 - 在所有@Async任务完成之前。这导致以下异常:

2017-08-31 16:10:54.212 ERROR 12663 --- [Hasselhoff-12] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected error occurred invoking async method 'public void de.xy.services.XYJobProcessor.process(java.util.Collection)'.org.springframework.orm.jpa.JpaSystemException: Session is closed!; nested exception is org.hibernate.SessionException: Session is closed!
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
        at de.xy.services.XYJobService$$EnhancerBySpringCGLIB$$6b9cb1ae.createXYJobsAndDelete(<generated>)
        at de.xy.services.XYJobProcessor.process(XYJobProcessor.java:24)
        at de.xy.services.XYJobProcessor$$FastClassBySpringCGLIB$$ccc40c8f.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.springframework.core.task.SimpleAsyncTaskExecutor$ConcurrencyThrottlingRunnable.run(SimpleAsyncTaskExecutor.java:268)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.SessionException: Session is closed!
        at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:132)
        at org.hibernate.internal.SessionImpl.getPersistenceContext(SessionImpl.java:2088)
        at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:340)
        at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282)
        at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465)
        at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963)
        at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339)
        at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)
        at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)
        at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61)
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
        ... 17 common frames omitted

有没有办法让Spring在关闭EntityManager之前等待@Async执行完成?或者这是一个错误吗?

1 个答案:

答案 0 :(得分:0)

感谢@ M.Deinum,我发现了如何避免这个问题:

使用ThreadPoolTaskExecutor(而不是SimpleAsyncTaskExecutor)并将其awaitTerminationSeconds属性设置为waitForTasksToCompleteOnShutdown设置为true可以解决我的问题

来自setAwaitTerminationSeconds的JavaDoc:

  

设置此执行程序的最大秒数   关闭时阻止以等待剩余任务完成   在容器的其余部分继续关闭之前执行它们   下。如果您的剩余任务很可能,这尤其有用   需要访问同样由其管理的其他资源   容器

这是我的问题的确切描述和解决方案。

相关问题