使用Spring Data和Hibernate时,如何正确执行后台线程?
我正在构建一个简单的Tomcat web应用程序,它使用Spring Data和Hibernate。有一个端点可以完成很多工作,因此我想将工作卸载到后台线程,以便在完成工作时Web请求不会挂起10分钟以上。所以我在组件扫描包中写了一个新的服务:
@Service
public class BackgroundJobService {
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
public void startJob(Runnable runnable) {
threadPoolTaskExecutor.execute(runnable);
}
}
然后在春季配置:ThreadPoolTaskExecutor
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
这一切都很棒。但是,问题来自Hibernate。在我的可运行中,查询只有一半的工作。我可以做:
MyObject myObject = myObjectRepository.findOne()
myObject.setSomething("something");
myObjectRepository.save(myObject);
但是如果我有延迟加载的字段,它会失败:
MyObject myObject = myObjectRepository.findOne()
List<Lazy> lazies = myObject.getLazies();
for(Lazy lazy : lazies) { // Exception
...
}
我收到以下错误:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.stackoverflow.MyObject.lazies, could not initialize proxy - no Session
因此,在我看来(Hibernate新手),新线程在这些自制线程上没有会话,但Spring Data会自动为HTTP请求线程创建新会话。
- 有没有办法从会话中手动启动新会话?
- 或者一种告诉线程池为我做这件事的方法?
- 做这种工作的标准做法是什么?
我已经能够通过从方法内部执行所有操作来解决这个问题,但我很快就发现这不是一个很好的解决方案,因为这不允许我使用对Web请求有效的方法。@Transactional
谢谢。