2011-06-28 153 views
1

我嘗試使用多線程來嘗試持久化對象時遇到問題。使用多線程的JPA持久性

詳情:

假設我有其中有PaymentGroup列表(一對多的關係)和PaymentGroup(再次一對多的關係)包含CreditTransfer列表的對象PaymentOrder

由於CreditTransfer數量巨大(以萬盧比),我已經根據PaymentGroup(基於一些業務邏輯) 和創建WORKER線程(一個線程每個PaymentGroup)形成PaymentOrder對象和分組它在數據庫中提交。

問題是,每個工作線程正在創建一個PaymentOrder(其中包含一組唯一的PaymentGroup s)。

所有實體的主鍵都是自動生成的。

因此有三個表格,1.PAYMENT_ORDER_MASTER,2.PAYMENT_GROUPS,3.CREDIT_TRANSFERS,全部由一對多關係映射。

因爲,當第二線程試圖堅持其組中的數據庫,該框架試圖堅持同一PaymentOrder,其前一個線程提交,交易失敗由於一些其他唯一字段約束(的PaymentOrder的校驗和)。

理想的情況下它必須是1..n..m(PaymentOrder - > PaymentGroup --> CreditTransfer`)

我需要實現的是如果在數據庫中沒有的PaymentOrder記項,表項時,它的存在,請勿在PAYMENT_ORDER_MASTER中輸入,但只能在PAYMENT_GROUPSCREDIT_TRANSFERS之間輸入。

我該如何克服這個問題,維護split-master-payment-order-using-groups邏輯和多線程?

回答

2

你有選擇。
1)原始但簡單,最後抓住關鍵違規錯誤,並重試你的插入沒有父母。假設你的父母是真正獨一無二的,你知道另一個線索就是父母......繼續與孩子們接觸。與其他選項相比,這可能表現不佳,但也許你會得到所需的流行音樂。如果你的父母和一個孩子的比例很高,那麼它會很好地工作。

2)改變你的閱讀一致性水平。它是特定於供應商的,但您有時可以閱讀未提交的交易。這將有助於您在提交之前看到其他線程的工作。這不是萬無一失的,你還必須執行#1,因爲另一個線程可以在讀取後潛入。但它可能會提高吞吐量,但代價是更復雜。根據RDBMS(或者它可能發生,但僅在數據庫級別,搞亂了其他應用程序!)

3)使用單線程使用者實現工作隊列。如果程序的主要昂貴工作在持久層級之前,那麼可以讓你的線程將他們的數據「插入」到一個工作隊列中,在這裏工作隊列沒有強制執行。然後讓單個線程從工作隊列中拉出並保留。工作隊列可以在內存中,另一個表中或供應商特定位置(Weblogic隊列,Oracle AQ等)中。如果程序的主要工作在持久化之前,則將THAT並行化並返回到插入的單個線程。您甚至可以讓您的客戶以「批量插入」模式工作。 Sweeeeeeeet。

4)放鬆你的約束。如果同一個孩子有兩個父母持有相同的信息,誰真的關心?我只是問問。如果您以後不需要父級信息的超級快速更新,並且您可以更改您的閱讀程序以瞭解它,則它可以很好地工作。它不會讓你在數據庫設計類「A」,但如果它的工作.....

5)實現傻傻的鎖表。我討厭這個解決方案,但它確實奏效---讓你的線程記下它在父「x」上工作,而沒有其他人能夠做它的第一個事務(和提交)。通常會導致相同的問題(以及其他問題 - 稍後清理記錄等),但可以在子插入緩慢且單行插入速度很快時起作用。你仍然會碰撞,但更少。

0

休眠會話不是線程安全的。底層Hibernate的JDBC連接不是線程安全的。考慮多線程處理業務邏輯,以便每個線程都可以使用它自己的Hibernate會話和JDBC連接。通過使用線程池,您可以通過添加限制併發線程數量的能力來進一步改進代碼。