对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

JPA

Spring JPA 位于 org.springframework.orm.jpa 包下,为 Java 持久化 API 提供了全面的支持,其集成方式类似于 Hibernate 的集成,并且能够感知底层实现,从而提供额外的功能。spring-doc.cadn.net.cn

在 Spring 环境中设置 JPA 的三种选项

Spring JPA 支持提供了三种方式来配置应用程序用于获取实体管理器(Entity Manager)的 JPA EntityManagerFactoryspring-doc.cadn.net.cn

使用LocalEntityManagerFactoryBean

您仅可在简单的部署环境中使用此选项,例如独立应用程序和集成测试。spring-doc.cadn.net.cn

LocalEntityManagerFactoryBean 创建一个适用于简单部署环境的 EntityManagerFactory, 在这种环境中,应用程序仅使用 JPA 进行数据访问。 该工厂 Bean 使用 JPA 的 PersistenceProvider 自动检测机制(根据 JPA 的 Java SE 启动引导方式), 在大多数情况下,您只需指定持久化单元名称即可。以下 XML 示例配置了这样一个 Bean:spring-doc.cadn.net.cn

<beans>
	<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="myPersistenceUnit"/>
	</bean>
</beans>

这种形式的 JPA 部署最为简单,但也最受限制。您无法引用已有的 JDBC DataSource Bean 定义,也不支持全局事务。此外,持久化类的织入(字节码转换)是特定于 JPA 提供商的,通常需要在启动时指定一个特定的 JVM 代理。此选项仅适用于独立应用程序和测试环境,这也是 JPA 规范所设计的目标场景。spring-doc.cadn.net.cn

从 JNDI 获取 EntityManagerFactory

在部署到 Jakarta EE 服务器时,您可以使用此选项。请查阅您所用服务器的文档,了解如何将自定义的 JPA 提供商部署到服务器中,从而使用不同于服务器默认的 JPA 提供商。spring-doc.cadn.net.cn

从 JNDI 获取 EntityManagerFactory(例如在 Jakarta EE 环境中),只需更改 XML 配置即可,如下例所示:spring-doc.cadn.net.cn

<beans>
	<jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>

此操作假定使用标准的 Jakarta EE 引导方式。Jakarta EE 服务器会自动检测持久化单元(实际上是指应用程序 JAR 包中的 META-INF/persistence.xml 文件)以及 Jakarta EE 部署描述符(例如 persistence-unit-ref)中的 web.xml 条目,并为这些持久化单元定义环境命名上下文位置。spring-doc.cadn.net.cn

在这种场景下,整个持久化单元的部署(包括对持久化类进行织入(字节码转换))均由 Jakarta EE 服务器负责。JDBC DataSource 通过 JNDI 位置在 META-INF/persistence.xml 文件中定义。EntityManager 的事务与服务器的 JTA 子系统集成。Spring 仅使用所获取的 EntityManagerFactory,通过依赖注入将其传递给应用程序对象,并管理该持久化单元的事务(通常通过 JtaTransactionManager)。spring-doc.cadn.net.cn

如果在同一个应用程序中使用多个持久化单元,则通过 JNDI 获取的这些持久化单元的 Bean 名称应与应用程序用于引用它们的持久化单元名称相匹配(例如,在 @PersistenceUnit@PersistenceContext 注解中)。spring-doc.cadn.net.cn

使用LocalContainerEntityManagerFactoryBean

你可以在基于 Spring 的应用程序环境中使用此选项以获得完整的 JPA 功能。 这包括 Tomcat 等 Web 容器、独立应用程序,以及具有复杂持久化需求的集成测试。spring-doc.cadn.net.cn

LocalContainerEntityManagerFactoryBean 提供了对 EntityManagerFactory 配置的完全控制,适用于需要细粒度自定义的环境。LocalContainerEntityManagerFactoryBean 会基于 PersistenceUnitInfo 文件、所提供的 persistence.xml 策略以及指定的 dataSourceLookup 创建一个 loadTimeWeaver 实例。因此,可以在 JNDI 之外使用自定义数据源,并控制织入(weaving)过程。以下示例展示了一个典型的 LocalContainerEntityManagerFactoryBean 的 bean 定义:spring-doc.cadn.net.cn

<beans>
	<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="someDataSource"/>
		<property name="loadTimeWeaver">
			<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
		</property>
	</bean>
</beans>

以下示例展示了一个典型的 persistence.xml 文件:spring-doc.cadn.net.cn

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
	<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
		<mapping-file>META-INF/orm.xml</mapping-file>
		<exclude-unlisted-classes/>
	</persistence-unit>
</persistence>
<exclude-unlisted-classes/> 快捷方式表示不应扫描带注解的实体类。 显式设置为 'true' 的值(<exclude-unlisted-classes>true</exclude-unlisted-classes/>)也表示不进行扫描。 而 <exclude-unlisted-classes>false</exclude-unlisted-classes/> 则会触发扫描。 不过,如果您希望执行实体类扫描,我们建议省略 exclude-unlisted-classes 元素。

使用 LocalContainerEntityManagerFactoryBean 是最强大的 JPA 设置选项,允许在应用程序内部进行灵活的本地配置。它支持链接到现有的 JDBC DataSource,同时支持本地事务和全局事务等。然而,它也对运行环境提出了要求,例如,如果持久化提供程序需要字节码转换,则必须提供具备织入(weaving)能力的类加载器。spring-doc.cadn.net.cn

此选项可能与 Jakarta EE 服务器内置的 JPA 功能发生冲突。在完整的 Jakarta EE 环境中,请考虑从 JNDI 获取您的 EntityManagerFactory。 或者,在您的 persistenceXmlLocation 定义中指定一个自定义的 LocalContainerEntityManagerFactoryBean(例如, META-INF/my-persistence.xml),并在您的应用程序 JAR 文件中仅包含具有该名称的持久化描述文件。由于 Jakarta EE 服务器仅查找默认的 META-INF/persistence.xml 文件,因此会忽略此类自定义的持久化单元,从而避免与 Spring 驱动的 JPA 配置发生冲突。(例如,这适用于 Resin 3.1。)spring-doc.cadn.net.cn

何时需要加载时织入?

并非所有的 JPA 提供商都需要 JVM 代理。Hibernate 就是一个不需要代理的例子。 如果你的提供商不需要代理,或者你有其他替代方案,例如通过自定义编译器或 Ant 任务在构建时进行增强,那么就不应使用加载时织入器(load-time weaver)。spring-doc.cadn.net.cn

LoadTimeWeaver 接口是 Spring 提供的一个类,它允许以特定方式插入 JPA 的 ClassTransformer 实例,具体方式取决于运行环境是 Web 容器还是应用服务器。通过代理(agent)来挂钩(hook)https://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html 通常效率不高。这类代理作用于整个虚拟机,并检查每一个被加载的类,这在生产服务器环境中通常是不希望出现的行为。spring-doc.cadn.net.cn

Spring 提供了多种环境下的 LoadTimeWeaver 实现,使得 ClassTransformer 实例仅对每个类加载器生效,而不是对每个虚拟机生效。spring-doc.cadn.net.cn

有关 xref page 的实现及其配置(无论是通用配置还是针对各种平台(如 Tomcat、JBoss 和 WebSphere)的定制配置),请参阅 AOP 章节中的Spring 配置以获取更多详细信息。spring-doc.cadn.net.cn

Spring 配置中所述,您可以使用 LoadTimeWeaver 注解或 @EnableLoadTimeWeaving XML 元素来配置一个上下文范围的 context:load-time-weaver。所有 JPA 的 LocalContainerEntityManagerFactoryBean 实例会自动检测并使用该全局织入器。以下示例展示了设置加载时织入器的推荐方式,它能够自动检测运行平台(例如 Tomcat 支持织入的类加载器或 Spring 的 JVM 代理),并将织入器自动传播给所有支持织入功能的 Bean:spring-doc.cadn.net.cn

<context:load-time-weaver/>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	...
</bean>

然而,如果需要,你可以通过 loadTimeWeaver 属性手动指定一个专用的织入器(weaver),如下例所示:spring-doc.cadn.net.cn

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="loadTimeWeaver">
		<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
	</property>
</bean>

无论LTW(加载时织入)如何配置,通过使用这种技术,依赖于字节码增强的JPA应用程序都可以在目标平台(例如Tomcat)上运行,而无需使用Java代理。这一点尤其重要,因为当托管的应用程序依赖于不同的JPA实现时,JPA转换器仅在类加载器级别应用,从而彼此隔离。spring-doc.cadn.net.cn

处理多个持久化单元

对于依赖多个持久化单元位置(例如,存储在类路径中多个 JAR 文件内)的应用程序,Spring 提供了 PersistenceUnitManager 作为中央存储库,以避免执行代价高昂的持久化单元发现过程。默认实现允许指定多个位置。这些位置会被解析,并随后通过持久化单元名称进行检索。(默认情况下,会在类路径中搜索 META-INF/persistence.xml 文件。)以下示例配置了多个位置:spring-doc.cadn.net.cn

<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
	<property name="persistenceXmlLocations">
		<list>
			<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
			<value>classpath:/my/package/**/custom-persistence.xml</value>
			<value>classpath*:META-INF/persistence.xml</value>
		</list>
	</property>
	<property name="dataSources">
		<map>
			<entry key="localDataSource" value-ref="local-db"/>
			<entry key="remoteDataSource" value-ref="remote-db"/>
		</map>
	</property>
	<!-- if no datasource is specified, use this one -->
	<property name="defaultDataSource" ref="remoteDataSource"/>
</bean>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="persistenceUnitManager" ref="pum"/>
	<property name="persistenceUnitName" value="myCustomUnit"/>
</bean>

默认实现允许在将 PersistenceUnitInfo 实例传递给 JPA 提供程序之前对其进行自定义,既可以通过声明式方式(通过其属性,这些属性会影响所有托管的持久化单元),也可以通过编程方式(通过 PersistenceUnitPostProcessor,它允许选择特定的持久化单元)。如果没有指定 PersistenceUnitManager,则会创建一个并在内部由 LocalContainerEntityManagerFactoryBean 使用。spring-doc.cadn.net.cn

后台引导初始化

LocalContainerEntityManagerFactoryBean 通过 bootstrapExecutor 属性支持后台引导,如下例所示:spring-doc.cadn.net.cn

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="bootstrapExecutor">
		<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
	</property>
</bean>

实际的 JPA 提供商启动过程会被委托给指定的执行器,然后与应用程序的启动线程并行运行。所暴露的 EntityManagerFactory 代理可以被注入到其他应用程序组件中,甚至能够响应 EntityManagerFactoryInfo 配置的检查。然而,一旦其他组件开始访问实际的 JPA 提供商(例如,调用 createEntityManager),这些调用将被阻塞,直到后台启动过程完成。特别是当你使用 Spring Data JPA 时,请确保为其仓库也配置延迟启动。spring-doc.cadn.net.cn

基于 JPA 实现 DAO:EntityManagerFactoryEntityManager

尽管 EntityManagerFactory 实例是线程安全的,但 EntityManager 实例不是。 根据 JPA 规范的定义,注入的 JPA EntityManager 的行为类似于从应用服务器的 JNDI 环境中获取的 EntityManager。 它会将所有调用委托给当前事务中的 EntityManager(如果存在的话);否则,它会在每次操作时回退到新创建的 EntityManager,从而实际上使其使用具备线程安全性。

可以通过注入的 EntityManagerFactoryEntityManager 编写不依赖任何 Spring 组件的纯 JPA 代码。如果启用了 @PersistenceUnit,Spring 就能够识别字段级别和方法级别上的 @PersistenceContextPersistenceAnnotationBeanPostProcessor 注解。以下示例展示了一个使用 @PersistenceUnit 注解的纯 JPA DAO 实现:spring-doc.cadn.net.cn

public class ProductDaoImpl implements ProductDao {

	private EntityManagerFactory emf;

	@PersistenceUnit
	public void setEntityManagerFactory(EntityManagerFactory emf) {
		this.emf = emf;
	}

	public Collection loadProductsByCategory(String category) {
		EntityManager em = this.emf.createEntityManager();
		try {
			Query query = em.createQuery("from Product as p where p.category = ?1");
			query.setParameter(1, category);
			return query.getResultList();
		}
		finally {
			if (em != null) {
				em.close();
			}
		}
	}
}
class ProductDaoImpl : ProductDao {

	private lateinit var emf: EntityManagerFactory

	@PersistenceUnit
	fun setEntityManagerFactory(emf: EntityManagerFactory) {
		this.emf = emf
	}

	fun loadProductsByCategory(category: String): Collection<*> {
		val em = this.emf.createEntityManager()
		val query = em.createQuery("from Product as p where p.category = ?1");
		query.setParameter(1, category);
		return query.resultList;
	}
}

上述 DAO 不依赖于 Spring,但仍能很好地融入 Spring 应用上下文。此外,该 DAO 利用注解来要求注入默认的 EntityManagerFactory,如下例所示的 bean 定义:spring-doc.cadn.net.cn

<beans>

	<!-- bean post-processor for JPA annotations -->
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

	<bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

作为显式定义 PersistenceAnnotationBeanPostProcessor 的替代方案, 请考虑在您的应用程序上下文配置中使用 Spring 的 context:annotation-config XML 元素。 这样做会自动注册所有用于基于注解配置的 Spring 标准后处理器, 包括 CommonAnnotationBeanPostProcessor 等。spring-doc.cadn.net.cn

考虑以下示例:spring-doc.cadn.net.cn

<beans>

	<!-- post-processors for all standard config annotations -->
	<context:annotation-config/>

	<bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

此类 DAO 的主要问题在于它总是通过工厂创建一个新的 EntityManager。你可以通过请求注入一个事务型的 EntityManager(也称为“共享 EntityManager”,因为它是实际事务型 EntityManager 的一个共享、线程安全的代理)来避免这一问题,而不是注入工厂。以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

public class ProductDaoImpl implements ProductDao {

	@PersistenceContext
	private EntityManager em;

	public Collection loadProductsByCategory(String category) {
		Query query = em.createQuery("from Product as p where p.category = :category");
		query.setParameter("category", category);
		return query.getResultList();
	}
}
class ProductDaoImpl : ProductDao {

	@PersistenceContext
	private lateinit var em: EntityManager

	fun loadProductsByCategory(category: String): Collection<*> {
		val query = em.createQuery("from Product as p where p.category = :category")
		query.setParameter("category", category)
		return query.resultList
	}
}

@PersistenceContext 注解有一个名为 type 的可选属性,默认值为 PersistenceContextType.TRANSACTION。您可以使用此默认值来获取一个共享的 EntityManager 代理。另一种选项 PersistenceContextType.EXTENDED 则完全不同。它会生成所谓的扩展型 EntityManager,该对象不是线程安全的,因此不能用于并发访问的组件中,例如 Spring 管理的单例 Bean。扩展型 EntityManager 实例仅应用于有状态的组件中,例如存储在会话(session)中的组件,其生命周期并不绑定到当前事务,而是完全由应用程序控制。spring-doc.cadn.net.cn

方法级和字段级注入

你可以在类中的字段或方法上应用表示依赖注入的注解(例如 @PersistenceUnit@PersistenceContext)——因此有了“方法级注入”和“字段级注入”的说法。字段级注解简洁且更易于使用,而方法级注解则允许对注入的依赖项进行进一步处理。在这两种情况下,成员的可见性(public、protected 或 private)都无关紧要。spring-doc.cadn.net.cn

类级别的注解呢?spring-doc.cadn.net.cn

在 Jakarta EE 平台上,它们用于声明依赖关系,而不是用于资源注入。spring-doc.cadn.net.cn

所注入的 EntityManager 是由 Spring 管理的(能够感知当前正在进行的事务)。 尽管新的 DAO 实现使用了方法级别的 EntityManager 注入, 而非 EntityManagerFactory,但由于使用了注解, 因此无需更改 bean 的定义。spring-doc.cadn.net.cn

这种 DAO 风格的主要优势在于它仅依赖于 Java Persistence API。 无需导入任何 Spring 类。此外,由于 Spring 容器能够识别 JPA 注解, 因此依赖注入会自动应用。从非侵入性的角度来看,这一点非常有吸引力, 对 JPA 开发者来说也感觉更加自然。spring-doc.cadn.net.cn

基于 实现 DAO@Autowired(通常使用基于构造函数的注入)

@PersistenceUnit@PersistenceContext 只能声明在方法和字段上。 那么,能否通过构造函数和其他 @Autowired 注入点来提供 JPA 资源呢?spring-doc.cadn.net.cn

只要目标被定义为一个 bean(例如通过 EntityManagerFactory),@Autowired 就可以轻松地通过构造函数以及 LocalContainerEntityManagerFactoryBean 字段/方法进行注入。 注入点会按原样根据类型匹配原始的 EntityManagerFactory 定义。spring-doc.cadn.net.cn

然而,@PersistenceContext 风格的共享 EntityManager 引用无法开箱即用地用于普通的依赖注入。为了使其能够按类型匹配(如 @Autowired 所需),请考虑为您的 SharedEntityManagerBean 定义配置一个 EntityManagerFactory 作为配套组件:spring-doc.cadn.net.cn

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	...
</bean>

<bean id="em" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
	<property name="entityManagerFactory" ref="emf"/>
</bean>

或者,您可以基于 @Bean 定义一个 SharedEntityManagerCreator 方法:spring-doc.cadn.net.cn

@Bean("em")
public static EntityManager sharedEntityManager(EntityManagerFactory emf) {
	return SharedEntityManagerCreator.createSharedEntityManager(emf);
}

在存在多个持久化单元的情况下,每个 EntityManagerFactory 定义都需要搭配一个对应的 EntityManager Bean 定义,理想情况下应使用与特定 EntityManagerFactory 定义相匹配的限定符(qualifier),以便通过 @Autowired @Qualifier("…​") 来区分不同的持久化单元。spring-doc.cadn.net.cn

Spring 驱动的 JPA 事务

我们强烈建议您阅读声明式事务管理, 如果您尚未阅读的话,以更详细地了解 Spring 的声明式事务支持。

JPA 推荐的策略是通过 JPA 自带的事务支持来实现本地事务。Spring 的 JpaTransactionManager 针对任何常规的 JDBC 连接池(无需 XA 支持),提供了许多与本地 JDBC 事务相同的功能(例如事务特定的隔离级别和资源级别的只读优化)。spring-doc.cadn.net.cn

Spring JPA 还允许配置的 JpaTransactionManager 向访问相同 DataSource 的 JDBC 访问代码公开 JPA 事务,前提是所注册的 JpaDialect 支持获取底层的 JDBC Connection。 Spring 为 EclipseLink 和 Hibernate 的 JPA 实现提供了相应的方言(dialect)。 有关 #orm-jpa-dialect 机制的详细信息,请参见下一节spring-doc.cadn.net.cn

理解JpaDialectJpaVendorAdapter

作为一种高级特性,JpaTransactionManagerAbstractEntityManagerFactoryBean 的子类允许通过 JpaDialect bean 属性传入一个自定义的 jpaDialect。通过 JpaDialect 的实现,通常以特定于厂商的方式,可以启用 Spring 支持的以下高级特性:spring-doc.cadn.net.cn

这对于特殊的事务语义以及异常的高级转换尤其有价值。默认实现(DefaultJpaDialect)不提供任何特殊功能,如果需要前面列出的特性,则必须指定相应的方言。spring-doc.cadn.net.cn

作为一种更为通用的提供者适配机制,主要面向 Spring 功能完备的 LocalContainerEntityManagerFactoryBean 配置,JpaVendorAdapterJpaDialect 的功能与其他特定 JPA 提供商的默认设置结合起来。分别指定 HibernateJpaVendorAdapterEclipseLinkJpaVendorAdapter 是为 Hibernate 或 EclipseLink 自动配置 EntityManagerFactory 的最便捷方式。请注意,这些提供者适配器主要是为配合 Spring 管理的事务(即与 JpaTransactionManager 一起使用)而设计的。

请参阅 JpaDialectJpaVendorAdapter 的 Javadoc, 以获取更多关于其操作及其在 Spring JPA 支持中如何使用的详细信息。spring-doc.cadn.net.cn

使用 JTA 事务管理设置 JPA

作为 JpaTransactionManager 的替代方案,Spring 还允许通过 JTA 实现多资源事务协调,无论是在 Jakarta EE 环境中,还是使用独立的事务协调器(例如 Atomikos)。除了选择 Spring 的 JtaTransactionManager 而非 JpaTransactionManager 外,你还需要执行以下几个额外步骤:spring-doc.cadn.net.cn

  • 底层的 JDBC 连接池需要支持 XA,并且必须与您的事务协调器集成。这在 Jakarta EE 环境中通常很简单,只需通过 JNDI 暴露一种不同类型的 DataSource 即可。具体细节请参阅您的应用服务器文档。类似地,独立的事务协调器通常也会提供特殊的、已集成 XA 的 DataSource 变体。同样,请查阅其相关文档。spring-doc.cadn.net.cn

  • JPA 的 EntityManagerFactory 设置需要针对 JTA 进行配置。这是特定于 JPA 提供商的,通常通过在 jpaProperties 上指定 LocalContainerEntityManagerFactoryBean 来设置一些特殊属性。以 Hibernate 为例,这些属性甚至与 Hibernate 的版本相关。详情请参阅 Hibernate 的官方文档。spring-doc.cadn.net.cn

  • Spring 的 HibernateJpaVendorAdapter 强制使用某些面向 Spring 的默认设置,例如连接释放模式 on-close,该模式在 Hibernate 5.0 中与 Hibernate 自身的默认值一致,但在 Hibernate 5.1 及更高版本中不再一致。对于 JTA 配置,请确保将您的持久化单元事务类型声明为 "JTA"。或者,将 Hibernate 5.2 的 hibernate.connection.handling_mode 属性设置为 DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT,以恢复 Hibernate 自身的默认行为。相关说明请参见Hibernate 导致的应用服务器虚假警告spring-doc.cadn.net.cn

  • 或者,考虑直接从您的应用服务器获取 EntityManagerFactory(即通过 JNDI 查找,而不是使用本地声明的 LocalContainerEntityManagerFactoryBean)。服务器提供的 EntityManagerFactory 可能需要在服务器配置中进行特殊定义(这会降低部署的可移植性),但已针对服务器的 JTA 环境进行了配置。spring-doc.cadn.net.cn

原生 Hibernate 设置与用于 JPA 交互的原生 Hibernate 事务

原生的 LocalSessionFactoryBean 配置结合 HibernateTransactionManager 允许与 @PersistenceContext 以及其他 JPA 访问代码进行交互。Hibernate 的 SessionFactory 现在原生实现了 JPA 的 EntityManagerFactory 接口, 而 Hibernate 的 Session 句柄本身就是一个原生的 JPA EntityManager。 Spring 的 JPA 支持设施会自动检测原生的 Hibernate 会话。spring-doc.cadn.net.cn

因此,在许多场景中,这种原生的 Hibernate 配置可以替代标准 JPA 的 LocalContainerEntityManagerFactoryBeanJpaTransactionManager 组合,允许在同一本地事务中同时使用 SessionFactory.getCurrentSession()(以及 HibernateTemplate)和 @PersistenceContext EntityManager。这种配置还提供了更紧密的 Hibernate 集成和更高的配置灵活性,因为它不受 JPA 启动契约的约束。spring-doc.cadn.net.cn

在这种情况下,您不需要配置 HibernateJpaVendorAdapter, 因为 Spring 原生的 Hibernate 设置提供了更多功能 (例如,自定义 Hibernate Integrator 配置、Hibernate 5.3 与 Bean 容器的集成, 以及对只读事务的更强优化)。最后但同样重要的是,您也可以通过 LocalSessionFactoryBuilder 来表达原生的 Hibernate 设置, 从而无缝地与 @Bean 风格的配置集成(无需使用 FactoryBean)。spring-doc.cadn.net.cn

LocalSessionFactoryBeanLocalSessionFactoryBuilder 支持后台引导(background bootstrapping),就像 JPA 的 LocalContainerEntityManagerFactoryBean 一样。 参见后台引导以了解简介。spring-doc.cadn.net.cn

LocalSessionFactoryBean 上,可通过 bootstrapExecutor 属性获得该功能。在编程方式使用的 LocalSessionFactoryBuilder 上,重载的 buildSessionFactory 方法接受一个引导执行器(bootstrap executor)参数。spring-doc.cadn.net.cn