2014-01-10 46 views
0

之前,我使用的是GlassFish v2ur1(這是我公司採用一個,我不能在這一點上升級)。我有一個EJB(ejbA)從定時器週期性地調用。在調用中,我正在讀取一個文件,爲每一行創建一個實體bean,並將實體bean持久化到一個db(PostgreSQL v9.2)。調用entitymanager.persist(EntityBean的)之後,HTTP調用是一個Servlet發出,傳遞的EntityBean的ID,進而調用到另一個EJB(ejbB)。 ejbB將JMS消息發送給另一個實體bean ejbC。這是一個生產系統,我必須進行HTTP調用,它會進一步處理數據。 ejbC與ejbA位於同一企業應用程序中,但使用不同的EntityManager。 ejbC收到id,從db中讀取記錄,修改記錄,並保存它。寫實體bean內容數據庫事務提交

我遇到的問題是實體Bean的數據不被存儲到數據庫,直到從計時器調用該交易完成後(見下文)(我的理解就是這樣EJB的工作)。當調用ejbB時,它無法用它收到的id在db中找到記錄。我試過幾個方法來獲得存儲在數據庫中的數據,從而EJBC可以找到它:

1)我嘗試設置沖洗模式ejbA堅持的EntityBean的時候COMMIT:

- em.setFlushMode(FlushModeType.COMMIT) 
- instantiate entity bean 
- em.persist(entityBean) 
- em.flush() 

但是,結果是相同的,到調用ejbC時,db中沒有記錄。

2)I創建ejbD並在其中添加了一個storeRecord方法(該方法仍然存在的EntityBean)與TransactionAttributeType.REQUIRES_NEW。這應該暫停ejbA的事務,啓動ejbD的事務,提交它並恢復ejbA的事務。同樣,這裏的結果是一樣的,到調用ejbC時,db中沒有記錄。我也看到這個解決方案的問題,當我調用storeRecord方法時,ejbA調用停止。沒有拋出異常,但我沒有看到EJB處理來自文件的更多行,即使有更多的行。它似乎中止了EJB調用,並且沒有任何跡象回滾事務。不確定這是否是GlassFish v2ur1錯誤。

如何確保數據被存儲到ejbA分貝,所以當EJBC被調用時,它可以找到在DB的記錄?順便說一句,還有其他事情在ejbA中進行,我不一定要提交。我想堅持我想要存儲到數據庫的entityBeans。

ejbA

ejbTimer called (txn starts) 
read file contents 
for each line 
    create entity bean 
    persist entity bean to db 
    make HTTP call to ejbB, passing id 
    <see ejbC> 
return (txn ends) 

ejbB

Processes data based on id 
Looks up JMS queue for ejbC 
Passes ejbC the id 

EJBC

ejb method called (txn starts) 
read record based on received id 
modify record and persist 
return (txn ends) 

回答

0

有兩件事情我沒有解決這個。 1)我向ejbB添加了遠程方法,它們執行與HTTP調用相同的功能。這樣對ejbB的調用就在同一個事務中。

Glenn Lane指出問題的根源在於事務繼續在從ejbA到ejbB的調用中,但是當ejbB將JMS消息發送到ejbC時它會結束......事務不會擴展到對ejbC的調用。這意味着,當id到達ejbC時,它就在一個新的事務中,一個不能看到ejbA持久化到db的數據。

2)我將entity bean存儲到ejbA中的db中,並且處於特殊狀態。當定時器調用ejbA返回時(因此txn提交),實體bean將被存儲。當定時器再次調用ejbA時,它會在這個特殊狀態下的db中查找記錄。然後它調用ejbB。 ejbB發送JMS消息。當ejbC獲取id時,它會在db中找到記錄(如之前在前一個txn中提交的那樣),更改它的狀態並繼續處理。

0

使用的事務隔離 「讀提交」,沒有其他的交易可以看到未提交所做的更改交易。你可以指定一個較低的事務隔離,但這對PostgreSQL沒有任何影響:它的「最混亂」行爲是讀取提交的,所以你根本無法用PostgreSQL來完成。 而且也不應該你

ejbA應該呼叫通過HTTP ejbB。 Servlet只能用於爲遠程客戶端請求提供服務,而不能提供內部服務。 ejbA應該直接連接並調用ejbB。如果ejbB中的方法註釋爲TransactionAttributeType.MANDATORYTransactionAttributeType.REQUIRED,那麼ejbB將看到由ejbA創建的實體,因爲它在同一事務下。

在ejbB中,持久化是不必要的:只需加載實體EntityManager並進行更改。

如果你是完全在這個斷點續傳機制的擺佈,你可以使用bean管理的事務,但是這是在做事情可怕的方式:

read file contents 
for each line 
    start transaction 
    create entity bean 
    persist entity bean to db 
    commit transaction 
    make HTTP call 
+0

格倫,謝謝你的迴應。我改變了我的代碼,將一個遠程接口添加到ejbB,ejbA現在調用(在持久化entityBean之後)而不是使用HTTP。但是,我看到的行爲是ejbB找不到entityBean ejbA持久化,因此它會創建一個新的。我給的例子被簡化了。 ejbA在堅持entityBean之後調用ejbB。但ejbB將JMS消息發送給另一個EJB,將其稱爲ejbD,ejbD執行entityBean的查找並創建一個新的,如果未找到。我不認爲這會改變任何事情,因爲它們仍然在同一個事務中執行。 –

+0

最好是更新示例以包含ejbD和JMS,創建一個新問題,或者只是留下評論中的信息? –

+0

如果ejbD由JMS調用(例如它是一個消息驅動的bean),那麼ejbD將不會在與ejbB相同的事務中運行。它可能會在ejbB完成之前運行。這聽起來像ejbD正在做的工作應該直接調用,而不是通過JMS延期。 –

相關問題