2011-09-01 112 views
9

在我們的J2EE應用程序中,我們使用EJB-3有狀態bean來允許前端代碼創建,修改和保存持久實體(通過JPA-2進行管理)。爲什麼我們必須在擴展的PersistenceContext中手動刷新()EntityManager?

它看起來是這樣的:

@LocalBean 
@Stateful 
@TransactionAttribute(TransactionAttributeType.NEVER) 
public class MyEntityController implements Serializable 
{ 
    @PersistenceContext(type = PersistenceContextType.EXTENDED) 
    private EntityManager em; 

    private MyEntity current; 

    public void create() 
    { 
     this.current = new MyEntity(); 
     em.persist(this.current); 
    } 

    public void load(Long id) 
    { 
     this.current = em.find(MyEntity.class, id); 
    } 

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    public void save() 
    { 
     em.flush(); 
    } 
} 

非常重要,以避免太早提交,只有save()方法是在一個事務中,所以如果我們調用create(),我們插入沒有在數據庫中。

奇怪的是,在save()方法中,我們必須調用em.flush()才能真正擊中數據庫。事實上,我試過並發現我們也可以撥打em.isOpen()em.getFlushMode(),以及任何與「時間相關」的東西。

我不明白這一點。由於save()處於事務中,我認爲在該方法結束時,事務將被提交,因此持久化實體管理器會自動刷新。爲什麼我必須手動刷新它?

感謝, 澤維爾

+0

不需要'flush()'。 'joinTransaction()'應該足以在你的事務性方法中保存你的修改。 –

回答

7

的完整解釋是直接和金屬,將會在交易受到質疑註冊了EntityManager沒有對象,直到你真正使用

我們在app-server-land將創建這些對象中的一個來執行flush()並將其註冊爲javax.transaction.TransactionSynchronizationRegistryjavax.transaction.Transaction。除非存在活動事務,否則無法完成此操作。

這就是它的長與短。

是的,應用程序服務器可以很好地保留它給予有狀態bean的資源列表,並在有狀態bean可能啓動或參與的每個事務中自動註冊它們。缺點是您完全失去了決定哪些事情發生在哪些交易中。也許你有2到3個不同的事務在不同的持久化單元上運行,並且正在將擴展持久化上下文中的工作彙總到一個特定的事務中。這確實是一個設計問題,應用程序服務器應該將這些決定留給應用程序本身。

您在交易中使用它,我們會將其註冊到交易中。這是基本合同。

側面說明,這取決於底層的EntityManager是如何處理的,到了EntityManager 任何持續通話可足以在交易結束時導致完全齊平。當然,flush()是最直接和最清楚的,但persist()甚至可能是find()

+1

Wooh,我花了一些時間來完全理解你的答案,但現在它是有道理的。謝謝!從JPA2.1說明書 –

+0

相關報價(用於持久性上下文傳播7.6.4.1要求)的非傳播性 持久上下文:'如果實體管理器被一個JTA事務中調用的,持久性上下文將 可以與JTA交易相關聯'。 –

0

如果您使用擴展的持久化上下文裏面非事務方法進行管理的實體所有的操作都排隊等待寫入到數據庫。一旦在事務上下文中的實體管理器上調用flush(),所有排隊的更改都將寫入數據庫。換句話說,事實上你有一個事務性方法,當方法退出時(如在CMT中),本身並不提交這些改變,但是實際上衝掉實體管理器。你可以找到這個過程here

+2

我看了本教程,但似乎有點混淆。 它表示「這意味着您調用的任何持久化,合併或移除方法實際上都不會導致JDBC執行,因此在您手動調用EntityManager.flush之前更新數據庫。」指向你:) 但在第二個例子中,它說「never()更新將在checkout()方法結束時提交」,並且此checkout()是空的,沒有任何刷新。你怎麼能解釋這個例子? 另外,在Adam Bien的Real World JavaEE Patterns中,GateWay模式也有一個空的保存方法:http://tinyurl.com/3o96xoh(幻燈片67)。 –

0

因爲沒有辦法知道「何時」的客戶端與會話(擴展範圍)來完成。

相關問題