2012-10-31 24 views
0

我使用Spring的事務支持和JPA(Hibernate)來堅持我的實體。一切工作都應該如此,但是我在處理一個請求中的部分更新時被卡住了:Spring內的兩個JPA EntityManage管理事務?

對於每個用戶(HTTP)請求,我必須將日誌條目寫入數據庫表,即使更新「主要」業務實體失敗(例如由於驗證錯誤)。所以我的第一個/主體事務get被回滾,但第二個(寫入日誌)應該提交。這似乎使用正確的傳播水平寫入日誌項工作:

@Repository 
@Transactional(propagation = Propagation.REQUIRES_NEW) 
public class UserTracker extends ... { 

    @PersistenceContext private EntityManager em; 

    public void log(...) { 
    // create log entity and persist it 
    ... 
    em.persist(log); 
    em.flush(); 
    } 

} 

我的問題是,但是,我得到了第二次交易注入相同的EntityManager在第一。因此,刷新實體管理器(在第二個事務提交時顯式或隱式地)也會從第一個事務中清除我的骯髒的業務實體。

我該如何補救?我想爲日誌記錄部分使用第二個乾淨而新鮮的EntityManager,我知道我可以通過編程方式打開一個EntityManager,但是在這種情況下是否有更清晰的/聲明式的「Spring方法」?

編輯:

我的問題可能會從事實幹,我的第二次交易被嵌套在我的主業事務中:

|-------------- A --------------X <- Rollback of main business transaction (A) 
        |--- B ---|  <- Commit of second log transaction (B) 

我已經解決了我的問題,序列化的兩筆交易:

|--------- A --------X |--- B ---| 

所以一切都很好了,但只是出於好奇:如果我會堅持我的第一種方法一nd不建議按照建議的方式使用JDBC:我將如何爲第二個(嵌套)事務配置實體管理器,以便爲新事務獲得新的實體管理器。這可以做到嗎?

回答

-1

我不確定爲什麼你遇到了你要報告的問題,如果你的日誌代碼和業務邏輯代碼有REQUIRE_NEW,那麼它們之間不應有任何干擾。我的代碼中有一個非常類似的設置。你確定交易在你認爲他們在哪裏被觸發嗎?您是使用代理交易還是aspectJ交易?

如果您正在使用代理交易,那麼您必須小心地通過代理來確保tx開始。

你可以做的另一件事是使用SpringJDBC模板進行用戶日誌記錄,讓@Repository對EntityManager和JDBCTemplate都做同樣的事情,不要用相同的方法混合它們。

+0

想一想,我的設置有點奇怪。當我試圖寫日誌時,我的主要業務交易仍然是開放的(我在這裏使用了一個Open-In-View模式)。我可以(也可能應該)序列化這兩個交易以避免副作用...... –