Multithreading Spring调度程序启动的任务线程
我们正在构建一个包含数据层、业务层、服务层。。。 它还有一个调度器,每5秒钟唤醒一次,并在数据库表中查找任务,如果有任务要执行,则会启动一个线程来执行该任务。 问题在于,在执行过程中,任务需要从数据层读取和更新实体,其中一些实体具有延迟加载,并且当它因延迟加载异常而崩溃时,会话会在时间之前关闭Multithreading Spring调度程序启动的任务线程,multithreading,spring,hibernate,jpa,Multithreading,Spring,Hibernate,Jpa,我们正在构建一个包含数据层、业务层、服务层。。。 它还有一个调度器,每5秒钟唤醒一次,并在数据库表中查找任务,如果有任务要执行,则会启动一个线程来执行该任务。 问题在于,在执行过程中,任务需要从数据层读取和更新实体,其中一些实体具有延迟加载,并且当它因延迟加载异常而崩溃时,会话会在时间之前关闭 ERROR: org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler - Unexpected error occ
ERROR: org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.soft1.pack1.data.entity.InitialAlignment.initialAlignment, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266)
at com.soft1.pack1.data.entity.InitialAlignment.getDefenses(InitialAlignment.java:80)
at com.soft1.pack1.data.entity.TaskMatch.run(TaskMatch.java:74)
at com.soft1.pack1.negocio.TaskTaskExecutor.TaskTaskExecutorMethod(TaskTaskExecutor.java:61)
at sun.reflect.GeneratedMethodAccessor40.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
我们认为我们的问题更多的是架构上的,而不是技术上的
编辑1:
来自@radai评论
InitialAlignment有一个名为defenses的属性,它在
定义为lazy的列表属性,并使用以下内容进行注释
@OneToManyfetch=FetchType.LAZY
数据库访问层使用hibernate。该层打开一个hibernate会话,获取一个实体,并在会话结束后关闭hibernate会话
我不能肯定这一点,但以下是我认为发生在你身上的事情: 您有某种使用hibernate的数据库访问层。该层打开一个hibernate会话,获取一个实体,并在会话结束后关闭hibernate会话 您的代码调用此层以获取InitialAlignment的实例 InitialAlignment有一个名为defenses的属性,它迭代一些定义为lazy的列表属性,并用@OneToManyfetch=FetchType.lazy之类的注释,这意味着它在使用之前不会从数据库中获取。但是,只能在创建InitialAlignment实例的hibernate会话仍处于活动状态时获取惰性属性。 您的task TaskMatch在单独的线程中运行,并被赋予此实体,它尝试访问lazy字段,但创建该对象的hibernate会话已关闭,因此hibernate无法返回数据库并获取列表,这就是您遇到的异常 最快的解决方案是更改列表字段上@OneToMany hibernate注释的fetch属性。尝试将@Transactional添加到计划方法中。这将为当前任务执行创建会话
祝你好运 你是对的,这就是问题所在。出于性能原因,我们希望保持延迟加载,而不使用即时获取。我们已经尝试应用事务注释,但是会话的范围没有到达线程。还有其他建议吗?谢谢在您的数据访问层中添加一个特殊的方法—类似于getAlignmentWithDefenses,它将返回一个完整的实体—通过使用HQL select from Alignment join fetch defenses或获取一个对齐并调用getDefenses,然后返回它。获取任务的对象时使用此方法。如果这是您唯一的用途,那么您最好去让fetch变得急切……但它不会是获取实体的相同TX