我正在構建一個使用Spring Data和Hibernate的簡單Tomcat webapp。有一個端點可以完成很多工作,所以我想將工作轉移到後臺線程,以便在完成工作時Web請求不會掛起10分鐘以上。所以,我在一個組件scan'd包了一個新服務:如何在使用Spring Data和Hibernate時正確地創建後臺線程?
@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
所以它看起來像我(休眠新手),新線程在這些自制線程上沒有會話,但Spring Data會自動爲HTTP請求線程創建新會話。
- 有沒有辦法在會話內手動啓動一個新的會話?
- 還是一種告訴線程池爲我做的方法?
- 做這類工作的標準做法是什麼?
我已經能夠解決它一點點從一個@Transactional
方法裏面做的一切,但我很快意識到這不是一個很好的解決方案,因爲這並不讓我使用的工作方法對Web請求來說很好。
謝謝。
部分問題是,我希望能夠在作業運行時更新作業的狀態。所以如果我把它全部包裝在單個事務中,那麼在最外層提交提交之前,狀態不會更新。除非我在這裏錯過了一些東西......這是完全可能的:) – Joel
你可以展示你的Runnable實現類,也許你的ObjectRepository? 我也很好奇你如何以及在哪裏打算髮布狀態更新。 基於http的網絡應用程序並不是那麼明顯。 – alobodzk
專門用於更新進程狀態:使用嵌套事務。確保你的JPA提供者支持他們。 – Virmundi