2011-12-23 172 views
6

我已經在過去構建了一些JPA的東西,每個DAO實例使用javax.persistence.EntityManager的實例;這是大多數例子的設置方式。JPA EntityManager靜態或實例?

public class BaseDaoThatEveryDaoExtends { 
    @PersistenceContext 
    private EntityManager entityManager; 
} 

我只是偶然發現了代碼,使用一個靜態javax.peristence.EntityMangerPersistenceContext註釋注入,建築師告訴我這不會引起問題,他們甚至從來沒有在JTA和集羣應用程序出現任何問題XA數據源:

public class BaseDaoThatEveryDaoExtends { 
    @PersistenceContext 
    private static EntityManager entityManager; 
} 

據我可以告訴這是一個反模式的EntityManager持有一些狀態信息,使之靜使得這整個國家應用廣泛。這也使得這些類非常難以測試。

還有沒有其他的缺點,這樣做或者這是使用EntityManager的標準呢?

回答

1

EntityManager的使用一個ThreadLocal,所以它可能是確定自從所有線程訪問它會被獨立地處理,以保持靜態引用它保持到它的數據。事實上,如果EJB上下文以靜態的方式保持在EntityManager上,並且使用單例模式,我不會感到驚訝。

就我個人而言,我不會以靜態方式定義它。這似乎沒有必要,最壞的情況可能會有一些不可預見的副作用。

的一個問題,我可以看到的是能力,不經意間從靜態方法訪問的EntityManager:

public class BaseDaoThatEveryDaoExtends { 
    @PersistenceContext 
    private static EntityManager entityManager; 

    public static void doSomeStaticWork(){ 
     ... 
     entityManager.doSomething; //NPE possible! 
    } 
} 

我能看到的EntityManager不被注入,從而在這種情況下,NPE。

除此之外,有可能是周圍測試的一些問題/使用EntityManager嘲諷。

+0

當一個人工構造DAO的實例而不是注入並調用實例方法時,NPE也很好。所以這不是一個真正的爭論。 – BalusC 2011-12-23 22:45:12

+0

除非您不必構建BaseDaoThatEveryDaoExtends,您只需調用BaseDaoThatEveryDaoExtends.doSomeStaticwork(),這可能導致NPE。 – 2011-12-23 22:47:35

0

EntityManagerFactory保證是線程安全的,所以我認爲這是「正確」的方式: 在線程不安全的地方使用EMF並保護EntityManger本身免受線程問題。

4

我認爲主要的風險是不是在EntityManager的本身,而是附加到實體管理器時使用它的應用程序上下文。

讓我們假設你有兩個不同的客戶端發出請求到服務器,都調用應用程序的兩種不同的方法,在不同的線程都在運行,但兩者使用相同的實體管理器。

據我所知實體管理器將連有一個單一的背景下,這種情況下會被兩個客戶端共享。每次將實例加載到上下文時,都將通過共享實體管理器提供給線程。如果他們篡改彼此的數據會發生什麼?如果他們使用不同的事務隔離配置會發生什麼?你怎麼能確定客戶端1不會改變客戶端2當前使用的數據?

如果其中一位客戶使上下文無效,其他人會做什麼?你如何處理併發這種方式?