2015-08-21 15 views
4

我明白這是一個難題,因爲它不僅取決於hibernate,而且還取決於我們使用它的特定方式。 我們在我們的應用程序中使用hibernate 4,可能是以一種錯誤的方式,但事實就是這樣。Hibernate是否支持併發讀取數據?

所以我們加載一個整體的類層次結構,並在一個大的語句中加入了子類表,並按照我們轉換成對象的150K行的順序。

由於對象有許多字段需要設置(〜100),我們想並行化迭代遍歷結果集並獲取單獨行的循環。這在Hibernate中可能嗎? Hibernate是否已經從DB接收到所有結果並可以使用這些數據來保存對象,因此我們可以使用多線程來加速獲取大型結果集?

這是否有意義,還是更好地更改數據結構和映射以擺脫多表連接?

事實上,加載150K這些對象需要一分鐘或0.3毫秒/實體。我們有更簡單的表和更多的條目,我們在0.02毫秒/實體下加載一個數量級。初始化階段後,我們不會加載其他實體,而整個DB需要5分鐘以上。

如果我們通過將類層次結構忽略到數據庫並切換到基於組合的數據結構來移除連接,那麼我們可能會以多個表加載爲代價獲得更簡單的表加載而不是複雜的連接,負荷組合爲一體。

但問題仍然存在:如果我們有這麼多行加載,並因此需要填寫每個對象的字段時調用很多setter,這可以並行嗎?

+0

好並行獲取策略是一種可能性,但恕我直言,你會增加系統的複雜性。同樣在這一刻,很難判斷這種解決方案的可擴展性。我的建議是(如果你有時間的話)審查數據對象並消除不需要的連接和數據。 – bornleo

回答

2

不,在Hibernate中沒有這樣的事情。但是,如果您提到的數據集彼此獨立,則可以同時在不同線程(一個線程和一個數據集中的會話)中加載您在不同會話(事務)中擁有的每個數據組。然後從所有線程中獲取結果。

此方法的額外好處是您還可以並行執行數據集的查詢。

+0

JPA中的問題是EntityManager被設計爲僅在單個線程中使用。如果你想並行加載數據,你需要將工作分成不同的實體管理者進行不同的交易。但是,如果您最終想要在一個實體管理器中擁有所有數據,則可以使用em.merge()將加載的實體附加到最終的EM中。但是這可能會執行更多的SQL查詢,然後在一個線程中獲取數據,因此加載速度更慢。 – OndrejM

+0

的確如此,但問題是,你真的需要在一個Hibernate會話中處理大量的數據嗎?如果是,然後在多線程中預先加載二級緩存中的所有內容,然後使用最終的EM讀取它,應該會產生更少的查詢量(在理想情況下,em.merge()會讀取L2緩存中的所有內容)。但即使沒有合併,如果'SomeEntity'的關聯位於二級緩存中,像'select * from SomeEntity'這樣的查詢將執行少得多的附加查詢。 –

0

如果您想要將所有實體提取到二級緩存中,那麼您確實可能想要提取所有數據,但我認爲這不是一個好主意。

我想你應該只緩存訪問最多的數據,而不是整個條目。這樣緩存將需要更少的空間,您不需要一次獲取整個結果集。

如果你真的想獲取所有的數據,我會建議另一種方法。

您可以使用Java併發來並行化多個線程上的提取,因此您設置了一個EexcutorService,它接受一個Callable並嘗試批量提取條目。

如果你有N個處理器,你可以使用N個工作線程來做到這一點。您將根實體ID間隔除以N,以便您可以獲得N個子區間。每個工作線程將處理一個這樣的間隔並分批加載數據。這樣你就不必同步N個工作線程,避免兩次加載相同的數據。由於無論如何ID通常都是編入索引的,因此根據實體ID對條目進行排序並從最後處理的ID開始獲取批次可能會顯着加速加載。

相關問題