JPA EntityManager静态或实例?

Phi*_*eLM 7 java hibernate jpa entitymanager

我在过去构建了一些JPA的东西,它们使用了javax.persistence.EntityManager每个DAO实例的一个实例; 这是大多数示例的设置方式.

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private EntityManager entityManager;
}
Run Code Online (Sandbox Code Playgroud)

我只是偶然发现使用注释注入的静态 代码,架构师告诉我这不会引起任何问题,即使在具有JTA和XA数据源的集群应用程序中也没有任何问题:javax.peristence.EntityMangerPersistenceContext

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private static EntityManager entityManager;
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这是一个反模式,因为它EntityManager保存一些状态信息并使其静态使整个状态应用程序广泛.这也使得课程很难测试.

这样做有其他缺点还是这是使用标准的方法EntityManager

Edw*_*rzo 6

我认为主要风险不在于EntityManager本身,而是在使用它时附加到实体管理器的应用程序上下文中.

假设您有两个不同的客户端向您的服务器发出请求,它们都调用应用程序的两种不同方法,两种方法都在不同的线程上运行,但都使用相同的实体管理器.

据我所知,实体管理器将附加一个上下文,这两个客户端将共享此上下文.每次将实例加载到上下文时,线程都可以通过共享实体管理器使用.如果他们篡改对方的数据会怎么样?如果他们使用不同的事务隔离配置会发生什么?您如何确定客户端1不会更改客户端2当前使用的数据?

如果其中一个客户端使上下文无效,另一个客户会怎么做?你如何以这种方式处理并发?


Joh*_*sen 3

EntityManager 使用线程本地保存其数据,因此可以保存对其的静态引用,因为访问它的所有线程都将被独立处理。事实上,如果 EJB 上下文使用单例模式以静态方式保留 EntityManager,我不会感到惊讶。

就我个人而言,我永远不会以静态的方式定义它。这似乎没有必要,最坏的情况下可能会产生一些不可预见的副作用。

我看到的一个问题是能够无意中从静态方法访问entityManager:

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private static EntityManager entityManager;

   public static void doSomeStaticWork(){
      ...
      entityManager.doSomething; //NPE possible!
   }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我可以看到 EntityManager 没有被注入并导致 NPE。

除此之外,使用 EntityManager 进行测试/模拟可能会存在一些问题。