问题描述
JPA 规范定义了两种配置和使用方式:
- 应用管理的持久化上下文
- 容器管理的持久化上下文
使用应用程序管理的持久化上下文方法,应用程序代码使用 EntityManager
直接创建 EntityManagerFactory
。使用容器管理的持久化上下文,容器负责这一点。
似乎这一切只与控制 EntityManager
实例(创建、销毁等)有关。
问题是。为什么我们在 PersistenceProvider
类中有两种不同的方法? (我的意思是使用不同的参数)
我的意思是这些:
public EntityManagerFactory createEntityManagerFactory(String emName,Map map)
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info,Map map)
第一个似乎是应用程序托管类型。它只适用于 persistence.xml
文件,因为它只能采用持久性单元的名称。第二个是容器管理类型。它可以接受 PersistenceUnitInfo
对象。为什么我不能将应用程序托管类型与自定义 PersistenceUnitInfo 参数一起使用?无论如何,这两种变体似乎都适用于容器。差异仅出现在控制 EntityManager
实例中。当我们谈论 EntityManagerFactory
的配置时,这个对象总是驻留在一个容器中,因为我可以用 @PersistenceUnit
注释注入它。
这看起来很奇怪,因为我仍然可以使用 <jta-data-source>
标记为应用程序托管类型指定数据源。我可以使用 java setter 方法对 Container 托管类型执行相同的操作。如果我可以做同样的事情,为什么我只能在一个变体中使用 XML 标记,而我可以在第二个变体中使用 java setter(java 配置)?
解决方法
最典型的 JPA 案例
因此,本术语中的“容器”是指 Java EE / Jakarta EE 容器(也称为“应用程序服务器”)。我认为这可能看起来如此令人困惑的原因是因为大多数文档面向典型的应用程序开发人员,但您询问的代码通常由 JPA 提供者和容器提供者负责。
在最典型的情况下,在 Java EE / Jakarta EE 容器中运行的应用程序不会使用这些 PersistenceProvider
方法。它可能会注入一个 EntityManager
(容器管理的持久性上下文)或注入一个 EntityManagerFactory
(应用管理的持久性上下文)。
PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info,Map map)
方法旨在让 JPA 提供程序允许 Java EE/Jakarta EE 容器创建 EMF,该 EMF 可能可用于容器管理和应用程序管理的持久性上下文。
在 Java SE 环境中,应用程序会调用 Persistence.createEntityManagerFactory(...)
,后者会找到一个 Provider 并调用它的 PersistenceProvider#createEntityManagerFactory
方法。在这里,应用也不需要自己调用 PersistenceProvider
。
因此,如果您有一个典型的应用,并且正在尝试找出要调用的 PersistenceProvider
方法,那么您可能走错了路,应该从更好的示例开始。
特殊情况
当您使用使用 persistence.xml 加载持久性上下文的典型方法时,这一切都运行良好,并为您处理,如上所述。但是,如果您的应用程序想要做一些不同的和自定义的事情,那么您可能想要自己调用 PersistenceProvider
。例如。 this 是一篇稍微讨论该主题的文章。使用这种方法,您最终可能会将您的应用程序绑定到特定的提供商。
如果有的话,我不确定规范对这种情况的确切说明。我会将其描述为具有更多“应用程序管理的持久性”的感觉,因为您肯定是自己创建 EntityManager,但我不确定这是否是正确或有用的描述。