返回介绍

11.2.1 配置实体管理器工厂

发布于 2024-08-17 00:45:49 字数 6151 浏览 0 评论 0 收藏 0

简单来讲,基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:

应用程序管理类型(Application-managed):当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开或关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在Java EE容器中的独立应用程序。

容器管理类型(Container-managed):实体管理器由Java EE创建和管理。应用程序根本不与实体管理器工厂打交道。相反,实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适用于Java EE容器,在这种情况下会希望在persistence.xml指定的JPA配置之外保持一些自己对JPA的控制。

以上的两种实体管理器实现了同一个EntityManager接口。关键的区别不在于EntityManager本身,而是在于EntityManager的创建和管理方式。应用程序管理类型的EntityManager是由EntityManagerFactory创建的,而后者是通过PersistenceProvider的createEntityManagerFactory()方法得到的。与此相对,容器管理类型的Entity ManagerFactory是通过PersistenceProvider的createContainerEntityManager Factory()方法获得的。

这对想使用JPA的Spring开发者来说又意味着什么呢?其实这并没太大的关系。不管你希望使用哪种EntityManagerFactory,Spring都会负责管理EntityManager。如果你使用的是应用程序管理类型的实体管理器,Spring承担了应用程序的角色并以透明的方式处理EntityManager。在容器管理的场景下,Spring会担当容器的角色。

这两种实体管理器工厂分别由对应的Spring工厂Bean创建:

LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManager-Factory;

LocalContainerEntityManagerFactoryBean生成容器管理类型的Entity-ManagerFactory。

需要说明的是,选择应用程序管理类型的还是容器管理类型的EntityManager Factory,对于基于Spring的应用程序来讲是完全透明的。当组合使用Spring和JPA时,处理EntityManagerFactory的复杂细节被隐藏了起来,数据访问代码只需关注它们的真正目标即可,也就是数据访问。

应用程序管理类型和容器管理类型的实体管理器工厂之间唯一值得关注的区别是在Spring应用上下文中如何进行配置。让我们先看看如何在Spring中配置应用程序管理类型的LocalEntityManagerFactoryBean,然后再看看如何配置容器管理类型的LocalContainerEntityManagerFactoryBean。

配置应用程序管理类型的JPA

对于应用程序管理类型的实体管理器工厂来说,它绝大部分配置信息来源于一个名为persistence.xml的配置文件。这个文件必须位于类路径下的META-INF目录下。

persistence.xml的作用在于定义一个或多个持久化单元。持久化单元是同一个数据源下的一个或多个持久化类。简单来讲,persistence.xml列出了一个或多个的持久化类以及一些其他的配置如数据源和基于XML的配置文件。如下是一个典型的persistence.xml文件,它是用于Spittr应用程序的:

因为在persistence.xml文件中包含了大量的配置信息,所以在Spring中需要配置的就很少了。可以通过以下的@Bean注解方法在Spring中声明LocalEntityManagerFactoryBean:

赋给persistenceUnitName属性的值就是persistence.xml中持久化单元的名称。

创建应用程序管理类型的EntityManagerFactory都是在persistence.xml中进行的,而这正是应用程序管理的本意。在应用程序管理的场景下(不考虑Spring时),完全由应用程序本身来负责获取EntityManagerFactory,这是通过JPA实现的PersistenceProvider做到的。如果每次请求EntityManagerFactory时都需要定义持久化单元,那代码将会迅速膨胀。通过将其配置在persistence.xml中,JPA就能够在这个特定的位置查找持久化单元定义了。

但借助于Spring对JPA的支持,我们不再需要直接处理PersistenceProvider了。因此,再将配置信息放在persistence.xml中就显得不那么明智了。实际上,这样做妨碍了我们在Spring中配置EntityManagerFactory(如果不是这样的话,我们可以提供一个Spring配置的数据源)。

鉴于以上的原因,让我们关注一下容器管理的JPA:

使用容器管理类型的JPA

容器管理的JPA采取了一个不同的方式。当运行在容器中时,可以使用容器(在我们的场景下是Spring)提供的信息来生成EntityManagerFactory。

你可以将数据源信息配置在Spring应用上下文中,而不是在persistence.xml中了。例如,如下的@Bean注解方法声明了在Spring中如何使用LocalContainerEntity-ManagerFactoryBean来配置容器管理类型的JPA:

这里,我们使用了Spring配置的数据源来设置dataSource属性。任何javax.sql.DataSource的实现都是可以的。尽管数据源还可以在persistence.xml中进行配置,但是这个属性指定的数据源具有更高的优先级。

jpaVendorAdapter属性用于指明所使用的是哪一个厂商的JPA实现。Spring提供了多个JPA厂商适配器:

EclipseLinkJpaVendorAdapter

HibernateJpaVendorAdapter

OpenJpaVendorAdapter

TopLinkJpaVendorAdapter(在Spring 3.1版本中,已经将其废弃了)

在本例中,我们使用Hibernate作为JPA实现,所以将其配置为Hibernate-JpaVendorAdapter:

有多个属性需要设置到厂商适配器上,但是最重要的是database属性,在上面我们设置了要使用的数据库是Hypersonic。这个属性支持的其他值如表11.1所示。

表11.1 Hibernate的JPA适配器支持多种数据库,可以通过其database属性配置使用哪个数据库

数据库平台

属性database的值

IBM DB2

DB2

Apache Derby

DERBY

H2

H2

Hypersonic

HSQL

Informix

INFORMIX

MySQL

MYSQL

Oracle

ORACLE

PostgresQL

POSTGRESQL

Microsoft SQL Server

SQLSERVER

Sybase

SYBASE

一些特定的动态持久化功能需要对持久化类按照指令(instrumentation)进行修改才能支持。在属性延迟加载(只在它们被实际访问时才从数据库中获取)的对象中,必须要包含知道如何查询未加载数据的代码。一些框架使用动态代理实现延迟加载,而有一些框架像JDO,则是在编译时执行类指令。

选择哪一种实体管理器工厂主要取决于如何使用它。但是,下面的小技巧可能会让你更加倾向于使用LocalContainerEntityManagerFactoryBean。

persistence.xml文件的主要作用就在于识别持久化单元中的实体类。但是从Spring 3.1开始,我们能够在LocalContainerEntityManagerFactoryBean中直接设置packagesToScan属性:

在这个配置中,LocalContainerEntityManagerFactoryBean会扫描com.habuma.spittr.domain包,查找带有@Entity注解的类。因此,没有必要在persistence.xml文件中进行声明了。同时,因为DataSource也是注入到LocalContainer-EntityManager FactoryBean中的,所以也没有必要在persistence.xml文件中配置数据库信息了。那么结论就是,persistence.xml文件完全没有必要存在了!你尽可以将其删除,让LocalContainerEntityManagerFactoryBean来处理这些事情。

从JNDI获取实体管理器工厂

还有一件需要注意的事项,如果将Spring应用程序部署在应用服务器中,EntityManagerFactory可能已经创建好了并且位于JNDI中等待查询使用。在这种情况下,可以使用Spring jee命名空间下的<jee:jndi-lookup>元素来获取对EntityManagerFactory的引用:

我们也可以使用如下的Java配置来获取EntityManagerFactory:

尽管这种方法没有返回EntityManagerFactory,但是它的结果就是一个EntityManagerFactory bean。这是因为它所返回的JndiObjectFactoryBean是FactoryBean接口的实现,它能够创建EntityManagerFactory。

不管你采用何种方式得到EntityManagerFactory,一旦得到这样的对象,接下来就可以编写Repository了。让我们开始吧。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文