【问题标题】:JPA EntityManager Static or Instance?JPA EntityManager 静态还是实例?
【发布时间】:2012-01-27 02:42:20
【问题描述】:

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

public class BaseDaoThatEveryDaoExtends {
   @PersistenceContext
   private EntityManager entityManager;
}

我刚刚偶然发现使用由PersistenceContext 注释注入的静态 javax.peristence.EntityManger 的代码,架构师告诉我这不会导致任何问题,即使在集群中他们也从未遇到任何问题带有 JTA 和 XA 数据源的应用程序:

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

据我所知,这是一种反模式,因为 EntityManager 包含一些状态信息,并将其设为静态会使整个状态应用程序更广泛。这也使得这些类很难测试。

这样做是否还有其他缺点,或者这是使用EntityManager 的标准方式?

【问题讨论】:

    标签: java hibernate jpa entitymanager


    【解决方案1】:

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

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      public class BaseDaoThatEveryDaoExtends {
         @PersistenceContext
         private static EntityManager entityManager;
      
         public static void doSomeStaticWork(){
            ...
            entityManager.doSomething; //NPE possible!
         }
      }
      

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

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

      【讨论】:

      • 当一个人手动构造一个 DAO 的实例而不是注入它并调用它的实例方法时,NPE 也很有可能。所以这不是一个真正的论点。
      • 除非您不必构造 BaseDaoThatEveryDaoExtends,否则您只需调用 BaseDaoThatEveryDaoExtends.doSomeStaticwork(),这可能会导致 NPE。
      【解决方案3】:

      EntityManagerFactory 保证是线程安全的,所以我认为这是“正确”的方式: 在线程不安全的地方使用 EMF 并保护 EntityManger 本身免受线程问题的影响。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多