![](/img/trans.png)
[英]Hibernate SessionFactory vs. JPA EntityManagerFactory
[英]Injecting EntityManager Vs. EntityManagerFactory
一個很長的問題,請耐心等待。
我們將Spring + JPA用於Web應用程序。 我的團隊正在討論在GenericDAO
注入EntityManagerFactory
(在APPFUSE提供的基於泛型的DAO,我們不會出於某種原因使用JpaDaosupport
)而不是注入EntityManager
。 我們正在使用“應用程序管理持久性”。
反對注入EntityManagerFactory
的論點是它太重而且不需要, EntityManager
做我們需要的。 此外,由於Spring會為每個Web請求創建一個新的DAO實例(我懷疑這一點),因此不會出現任何並發問題,因為同一個EntityManager
實例由兩個線程共享。
注入EFM的理由是,它是一個很好的做法,總是很好地擁有工廠的句柄。
我不確定哪種方法最好,有人可以賜教嗎?
優點和注入的EntityManagerFactory VS的EntityManager的缺點在Spring文檔都列明在這里 ,我不知道如果我能在改善。
這么說,你的問題中有一些要點應該被清除。
... Spring將為每個Web請求創建一個新的DAO實例...
這是不正確的。 如果您的DAO是一個Spring bean,那么它是一個單例,除非您通過bean定義中的scope
屬性進行配置。 為每個請求實例化DAO都會很瘋狂。
注入EMF的論點是,對於工廠來說,它是一個很好的做法。
這種說法並不真正有用。 一般的良好實踐表明,應該向一個對象注入完成其工作所需的最少合作者。
我正在放下我最終收集到的東西。 從Spring Reference中的“ 基於普通JPA實現DAO ”一節:
雖然EntityManagerFactory實例是線程安全的,但EntityManager實例不是。 注入的JPA EntityManager的行為類似於從應用程序服務器的JNDI環境獲取的EntityManager,如JPA規范所定義。 它將所有調用委托給當前的事務性EntityManager,如果有的話; 否則,它會回退到每個操作新創建的EntityManager,實際上使其使用線程安全。
這意味着根據JPA規范,EntityManager實例不是線程安全的,但如果Spring處理它們,它們將成為線程安全的。
如果您使用的是Spring,最好注入EntityManagers而不是EntityManagerFactory。
我認為這已經很好地涵蓋了,但只是為了強調幾點。
如果由Spring注入,DAO 默認為單例 。 您必須將范圍顯式設置為prototype,以便每次都創建一個新實例。
由@PersistenceContext注入的實體管理器是線程安全的 。
話雖這么說,我的多線程應用程序中的單例DAO確實存在一些問題。
我最終使DAO成為一個實例bean,並解決了這個問題。
因此,雖然文檔可能會說一件事,但您可能希望徹底測試您的應用程序。
跟進:
我認為我的一部分問題是我正在使用
@PersistenceContext(unitName = "unit",
type = PersistenceContextType.EXTENDED)
如果您使用PersistenceContextType.EXTENDED,請記住,如果我理解正確,您必須手動關閉事務。 有關更多信息,請參閱此主題。
另一個后續行動:
使用實例化DAO是一個非常糟糕的主意。 DAO的每個實例都有自己的持久性緩存,其他DAO bean無法識別對一個緩存的更改。 抱歉,不好的建議。
我發現在我們的DAO上設置@Repository Spring注釋並使用Spring管理的EntityManager並通過@PersistenceContext注釋注入是使一切工作流暢的最方便的方法。 您可以從共享EntityManager的線程安全性和異常轉換中受益。 默認情況下,如果您將來自管理器的多個DAO組合在一起,則共享的EntityManager將管理事務。 最后你會發現你的DAO會變得貧血。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.