2009-08-21 118 views
64

一個很長的問題,請耐心等待。注入EntityManager VS. EntityManagerFactory

我們使用Spring + JPA作爲Web應用程序。我的團隊正在注入(基於泛型的DAO,由APPFUSE提供的線路,我們不使用JpaDaosupport出於某種原因)在注入EntityManager之後注入EntityManagerFactory。我們正在使用「應用程序管理持久性」。

反對注射EntityManagerFactory的論據是它太重,所以不需要,EntityManager做我們需要的。另外,由於Spring會爲每個Web請求創建一個DAO的新實例(我懷疑這一點),所以不會有任何併發​​問題,因爲兩個線程共享相同的實例。

注射EFM的理由是,它是一個很好的實踐,總是有很好的辦法來處理工廠。

我不確定哪個是最好的方法,有人請賜教嗎?

+2

我進一步理解,當Spring注入EntityManager時,它是「容器管理持久性」,並且Spring使得Entitymanagers線程安全。 SB – 2009-08-21 06:10:44

回答

49

注入EntityManagerFactory與EntityManager的優點和缺點都在Spring文檔here中詳細說明,我不確定是否可以改進。

說到這個問題,應該清除一些問題。

...春天將創造的 爲每個Web請求一個DAO實例...

這是不正確的。如果你的DAO是一個Spring bean,那麼它是一個單例,除非你通過bean定義中的scope屬性來配置它。爲每個請求實例化一個DAO將是瘋狂的。

注入EMF的說法是, 它在一個很好的做法其所有 總是好的,有一個句柄 工廠。

這個說法並不是真的有水。一般的良好做法認爲,應該向一個對象注入最低限度的合作者來完成其工作。

6

我發現在我們的DAO上設置@Repository Spring註解,並讓Spring管理的EntityManager和@PersistenceContext註解注入是讓所有的東西都能流利地工作的最方便的方法。您受益於共享EntityManager和異常轉換的線程安全性。默認情況下,共享EntityManager將管理交易,如果您將多個來自經理的DAO組合在一起。最後你會發現你的DAO會變得貧血。

23

我放下了我最終收集的東西。從Spring參考一節「Implementing DAOs based on plain JPA」:

雖然EntityManagerFactory的實例是線程安全的,但EntityManager 情況並非如此。注入的JPA EntityManager的行爲類似於從應用服務器的JNDI環境中獲取的 EntityManager,如JPA規範所定義的 。它將所有調用委託給 當前事務型EntityManager(如果有);否則,它將每個操作的 降回到新創建的EntityManager,實際上使其線程安全的 使用成爲可能。

這意味着按照JPA規範,EntityManager實例不是線程安全的,但是如果Spring處理它們,它們將變爲線程安全的。

如果您使用Spring,最好注入EntityManagers而不是EntityManagerFactory。

9

我認爲這已經被很好的涵蓋,但只是爲了強調幾點。

  • 的DAO,如果由Spring注入,是 單默認。您必須將 明確將範圍設置爲原型 以每次創建一個新實例。

  • 通過 @PersistenceContext 注入實體管理器是線程安全的

這就是說,我確實在我的多線程應用程序中使用單例DAO時遇到了一些問題。 我最終使DAO成爲一個實例bean,並解決了這個問題。 因此,雖然文檔可能會說一件事,但您可能希望徹底測試您的應用程序。

後續:

我想我的問題的一部分是我使用

@PersistenceContext(unitName = "unit", 
    type = PersistenceContextType.EXTENDED) 

如果使用PersistenceContextType.EXTENDED,記住,你必須這樣做,如果我理解正確的話,手動關閉交易。有關更多信息,請參閱this線程。

另一個後續:

使用實例化DAO是一個非常糟糕的主意。 DAO的每個實例都將擁有自己的持久性緩存,並且對其中一個緩存的更改不會被其他DAO Bean識別。對不起,不好的建議。

相關問題