该软件包下提供的 Spring JPA 提供
对 Java 持久性的全面支持
API 以类似于与 Hibernate 集成的方式进行,同时了解
底层实现,以便提供额外的功能。org.springframework.orm.jpa
在 Spring 环境中设置 JPA 的三个选项
Spring JPA 支持提供了三种设置 JPA 的方法,应用程序使用该 JPA 来获取实体管理器。EntityManagerFactory
用LocalEntityManagerFactoryBean
您只能在简单的部署环境(如独立部署环境)中使用此选项 应用程序和集成测试。
创建适合
应用程序仅使用 JPA 进行数据访问的简单部署环境。
工厂 Bean 使用 JPA 自动检测机制(根据
添加到 JPA 的 Java SE 引导),并且在大多数情况下,要求您仅指定
持久性单元名称。下面的 XML 示例配置了这样的 bean:LocalEntityManagerFactoryBeanEntityManagerFactoryPersistenceProvider
<beans>
	<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="myPersistenceUnit"/>
	</bean>
</beans>
这种形式的 JPA 部署是最简单且最有限的。您不能引用
现有的 JDBC bean 定义,并且不支持全局事务
存在。此外,持久化类的编织(字节码转换)是
特定于提供程序,通常需要在启动时指定特定的 JVM 代理。这
选项仅适用于独立应用程序和测试环境,对于这些应用程序和测试环境
设计了 JPA 规范。DataSource
从 JNDI 获取 EntityManagerFactory
在部署到 Jakarta EE 服务器时,可以使用此选项。查看服务器的文档 了解如何将自定义 JPA 提供程序部署到您的服务器中,从而允许不同的 provider 而不是服务器的默认值。
从 JNDI 获取 (例如在 Jakarta EE 环境中),
是更改 XML 配置的问题,如下例所示:EntityManagerFactory
<beans>
	<jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>
此操作假定标准 Jakarta EE 引导。Jakarta EE 服务器自动检测
持久化单元(实际上是应用程序 jar 中的文件)和 Jakarta EE 部署描述符中的条目(例如,),并定义这些持久化单元的环境命名上下文位置。META-INF/persistence.xmlpersistence-unit-refweb.xml
在这种情况下,整个持久化单元部署,包括编织
(字节码转换)的持久化类,则取决于 Jakarta EE 服务器。JDBC 是通过文件中的 JNDI 位置定义的。 事务与服务器的 JTA 子系统集成。仅 Spring
使用获取的 ,通过
持久性单元的依赖关系注入和管理事务(通常
通过 )。DataSourceMETA-INF/persistence.xmlEntityManagerEntityManagerFactoryJtaTransactionManager
如果在同一应用程序中使用多个持久性单元,则此类
JNDI 检索到的持久性单元应与
application 用于引用它们(例如,IN 和 Annotations)。@PersistenceUnit@PersistenceContext
用LocalContainerEntityManagerFactoryBean
您可以在基于 Spring 的应用程序环境中使用此选项来获得完整的 JPA 功能。 这包括 Web 容器(如 Tomcat)、独立应用程序以及 具有复杂持久性要求的集成测试。
可以完全控制配置,适用于满足以下条件的环境
需要精细的自定义。将基于文件创建一个实例,
提供的策略和指定的 .因此,
可以在 JNDI 之外使用自定义数据源并控制编织
过程。以下示例显示了 a 的典型 bean 定义:LocalContainerEntityManagerFactoryBeanEntityManagerFactoryLocalContainerEntityManagerFactoryBeanPersistenceUnitInfopersistence.xmldataSourceLookuploadTimeWeaverLocalContainerEntityManagerFactoryBean
<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
<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>
该快捷方式表示不扫描
带注释的实体类应该出现。显式的 'true' 值
() 也表示不扫描。 会触发扫描。
但是,我们建议省略元素
如果您希望进行实体类扫描。<exclude-unlisted-classes/><exclude-unlisted-classes>true</exclude-unlisted-classes/><exclude-unlisted-classes>false</exclude-unlisted-classes/>exclude-unlisted-classes | 
使用 是最强大的 JPA 设置
选项,允许在应用程序内进行灵活的本地配置。它支持
链接到现有 JDBC ,支持本地和全局事务,并且
等等。但是,它也对运行时环境提出了要求,例如
如果持久性提供程序需要,则提供支持 Weaving 的类加载器的可用性
字节码转换。LocalContainerEntityManagerFactoryBeanDataSource
此选项可能与 Jakarta EE 服务器的内置 JPA 功能冲突。在
完整的 Jakarta EE 环境,请考虑从 JNDI 获取您的环境。
或者,在定义中指定自定义(例如
META-INF/my-persistence.xml),并在
应用程序 jar 文件。由于 Jakarta EE 服务器仅查找默认文件,因此它会忽略此类自定义持久性单元,因此,
避免与 Spring 驱动的 JPA 预先设置冲突。(这适用于 Resin 3.1,用于
示例。EntityManagerFactorypersistenceXmlLocationLocalContainerEntityManagerFactoryBeanMETA-INF/persistence.xml
该接口是 Spring 提供的类,它允许以特定方式插入 JPA 实例,具体取决于
environment 是 Web 容器或应用程序服务器。通过代理程序进行挂钩通常效率不高。代理针对整个虚拟机工作,并且
检查加载的每个类,这在生产中通常是不可取的
服务器环境。LoadTimeWeaverClassTransformerClassTransformers
Spring 为各种环境提供了许多实现,
让实例仅应用于每个类加载器,而不是
对于每个 VM。LoadTimeWeaverClassTransformer
请参阅 AOP 章节中的 Spring 配置
有关实施及其设置的更多见解
通用或针对各种平台(如 Tomcat、JBoss 和 WebSphere)进行定制。LoadTimeWeaver
如 Spring 配置中所述,您可以配置
使用 annotation 或 XML 元素进行上下文范围的调用。这样的全局 weaver 会自动被选中
按所有 JPA 实例。以下示例
显示设置加载时编织机的首选方法,提供自动检测
平台(例如 Tomcat 的具有 weaving 功能的类加载器或 Spring 的 JVM 代理)
以及将 Weaver 自动传播到所有可识别 Weaver 的 bean:LoadTimeWeaver@EnableLoadTimeWeavingcontext:load-time-weaverLocalContainerEntityManagerFactoryBean
<context:load-time-weaver/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	...
</bean>
但是,如果需要,您可以通过该属性手动指定专用编织器,如下例所示:loadTimeWeaver
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="loadTimeWeaver">
		<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
	</property>
</bean>
无论 LTW 是如何配置的,通过使用这种技术,依赖于 插桩可以在目标平台(例如 Tomcat)中运行,而无需代理。 当托管应用程序依赖于不同的 JPA 时,这一点尤其重要 实现,因为 JPA 转换器只应用于类加载器级别,而 因此,彼此隔离。
处理多个持久性单元
对于依赖多个持久化单元位置(存储在各种
JARS),Spring 提供了 to 作为
中央存储库,并避免 Persistence Units 发现过程,该过程可以是
贵。默认实现允许指定多个位置。这些位置是
解析,然后通过 Persistence Unit Name 检索。(默认情况下,类路径
将搜索文件。以下示例配置
多个地点:PersistenceUnitManagerMETA-INF/persistence.xml
<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>
默认实现允许自定义实例
(在它们被提供给 JPA 提供程序之前)要么声明地(通过其属性,要么
影响所有托管单位)或编程方式(通过 ,允许选择持久性单位)。如果未指定 no,则创建一个 .PersistenceUnitInfoPersistenceUnitPostProcessorPersistenceUnitManagerLocalContainerEntityManagerFactoryBean
后台引导
LocalContainerEntityManagerFactoryBean支持后台引导
该属性,如下例所示:bootstrapExecutor
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="bootstrapExecutor">
		<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
	</property>
</bean>
实际的 JPA 提供程序引导将移交给指定的执行程序,然后
并行运行,以执行应用程序引导线程。公开的代理可以注入到其他应用程序组件中,甚至能够响应配置检查。但是,一旦实际的 JPA 提供程序
正在被其他组件访问(例如,调用 ),这些
calls 会阻塞,直到后台引导完成。特别是,当您使用
Spring Data JPA,请确保还为其存储库设置延迟引导。EntityManagerFactoryEntityManagerFactoryInfocreateEntityManager
该快捷方式表示不扫描
带注释的实体类应该出现。显式的 'true' 值
() 也表示不扫描。 会触发扫描。
但是,我们建议省略元素
如果您希望进行实体类扫描。<exclude-unlisted-classes/><exclude-unlisted-classes>true</exclude-unlisted-classes/><exclude-unlisted-classes>false</exclude-unlisted-classes/>exclude-unlisted-classes | 
基于 JPA 实现 DAO:和EntityManagerFactoryEntityManager
尽管实例是线程安全的,但实例
不是。注入的 JPA 的行为类似于从
应用程序服务器的 JNDI 环境,如 JPA 规范所定义。它委派
对当前 transactional 的所有调用(如果有)。否则,它会回退
添加到新创建的 per 操作中,实际上使其使用线程安全。EntityManagerFactoryEntityManagerEntityManagerEntityManagerEntityManagerEntityManager | 
可以针对普通 JPA 编写代码,而没有任何 Spring 依赖项,方法是
使用注入的 或 .Spring 可以在字段和方法中理解 and 注解
level (如果启用了 a)。以下示例
显示了使用注解的普通 JPA DAO 实现:EntityManagerFactoryEntityManager@PersistenceUnit@PersistenceContextPersistenceAnnotationBeanPostProcessor@PersistenceUnit
- 
Java
 - 
Kotlin
 
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 利用注解来要求
注入默认的 ,如下例 bean 定义所示:EntityManagerFactory
<beans>
	<!-- bean post-processor for JPA annotations -->
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
	<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
作为显式定义 的替代方法 ,
考虑在应用程序中使用 Spring XML 元素
context 配置。这样做会自动注册所有 Spring 标准
后处理器 (post-processors) 用于基于注释的配置,包括 等。PersistenceAnnotationBeanPostProcessorcontext:annotation-configCommonAnnotationBeanPostProcessor
请考虑以下示例:
<beans>
	<!-- post-processors for all standard config annotations -->
	<context:annotation-config/>
	<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
这种 DAO 的主要问题是它总是创建一个新的
工厂。您可以通过请求事务性(也称为
“shared EntityManager”,因为它是实际事务的共享线程安全代理
EntityManager) 而不是工厂。以下示例显示了如何执行此操作:EntityManagerEntityManager
- 
Java
 - 
Kotlin
 
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
	}
}
该注释具有一个名为 的可选属性,该属性默认为
自。您可以使用此默认值来接收共享代理。替代项 , 是完全的
不同的事件。这导致了所谓的扩展 ,它不是
线程安全的,因此,不得在并发访问的组件中使用,例如
Spring 管理的单例 bean。只应该使用扩展实例
在有状态组件中,例如,驻留在会话中,其生命周期不与当前事务绑定,而是完全取决于
应用。@PersistenceContexttypePersistenceContextType.TRANSACTIONEntityManagerPersistenceContextType.EXTENDEDEntityManagerEntityManagerEntityManager
注入的 is 由 Spring 管理的(知道正在进行的事务)。
即使新的 DAO 实现使用方法级注入 an 而不是 an ,也不需要更改 bean 定义
由于 Comments 的使用。EntityManagerEntityManagerEntityManagerFactory
这种 DAO 风格的主要优点是它仅依赖于 Java 持久性 API。 不需要导入任何 Spring 类。此外,正如 JPA 注释所理解的那样, 注入由 Spring 容器自动应用。这很吸引人 非侵入性视角,对于 JPA 开发人员来说可能感觉更自然。
基于实现 DAO(通常使用基于构造函数的注入)@Autowired
@PersistenceUnit并且只能在方法和字段上声明。
通过构造函数和其他注入点提供 JPA 资源怎么样?@PersistenceContext@Autowired
EntityManagerFactory可以通过构造函数和字段/方法轻松注入
只要将目标定义为 bean,例如 via .
注入点按类型按原样匹配原始定义。@AutowiredLocalContainerEntityManagerFactoryBeanEntityManagerFactory
但是,-style 共享引用不适用于
开箱即用的常规依赖项注入。为了使其可用于基于类型的
根据需要进行匹配,考虑将 a 定义为
companion 的定义:@PersistenceContextEntityManager@AutowiredSharedEntityManagerBeanEntityManagerFactory
<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>
或者,您可以根据 :@BeanSharedEntityManagerCreator
@Bean("em")
public static EntityManager sharedEntityManager(EntityManagerFactory emf) {
	return SharedEntityManagerCreator.createSharedEntityManager(emf);
}
如果有多个持久化单元,则每个定义都需要
伴随着相应的 bean 定义,最好带有限定符
与 distinct 定义匹配以区分
持久性单元通过 .EntityManagerFactoryEntityManagerEntityManagerFactory@Autowired @Qualifier("…")
尽管实例是线程安全的,但实例
不是。注入的 JPA 的行为类似于从
应用程序服务器的 JNDI 环境,如 JPA 规范所定义。它委派
对当前 transactional 的所有调用(如果有)。否则,它会回退
添加到新创建的 per 操作中,实际上使其使用线程安全。EntityManagerFactoryEntityManagerEntityManagerEntityManagerEntityManagerEntityManager | 
Spring 驱动的 JPA 事务
| 我们强烈建议您阅读声明式事务管理, 如果您还没有这样做,请更详细地了解 Spring 的声明式事务支持。 | 
JPA 的推荐策略是通过 JPA 的本机事务进行本地事务处理
支持。Spring 提供了许多已知于本地
JDBC 事务(例如特定于事务的隔离级别和资源级别的
read-only optimizations),而无需
JTA 事务协调器和支持 XA 的资源。JpaTransactionManager
Spring JPA 还允许配置的 JPA 事务
添加到访问相同 的 JDBC 访问代码中,前提是已注册支持检索底层 JDBC 。Spring 提供
EclipseLink 和 Hibernate JPA 实现的方言。请参阅 下一节 以了解有关 的详细信息。JpaTransactionManagerDataSourceJpaDialectConnectionJpaDialect
对于实际资源连接的 JTA 样式的惰性检索, Spring 提供了一个
目标连接池对应的代理类:参见 LazyConnectionDataSourceProxy。
这对于 JPA 只读事务特别有用,因为 JPA 只读事务通常
从本地缓存进行处理,而不是命中数据库。DataSource
| 我们强烈建议您阅读声明式事务管理, 如果您还没有这样做,请更详细地了解 Spring 的声明式事务支持。 | 
理解和JpaDialectJpaVendorAdapter
作为高级功能, 和 子类 允许将自定义传递到 bean 属性中。实施可以启用以下高级
Spring 支持的功能,通常以特定于供应商的方式:JpaTransactionManagerAbstractEntityManagerFactoryBeanJpaDialectjpaDialectJpaDialect
- 
应用特定的事务语义(例如自定义隔离级别或事务 超时)
 - 
检索事务性 JDBC(用于向基于 JDBC 的 DAO 公开)
Connection - 
到 Spring 的高级翻译
PersistenceExceptionDataAccessException 
这对于特殊事务语义和高级
exception 的翻译。默认实现 () 会
不提供任何特殊功能,并且如果需要前面列出的功能,则您具有
以指定适当的方言。DefaultJpaDialect
作为一个更广泛的提供程序适配工具,主要针对 Spring 的全功能设置,它结合了
功能。指定 or 是最方便的
为 Hibernate 或 EclipseLink 自动配置设置的方式,
分别。请注意,这些提供程序适配器主要设计用于
Spring 驱动的事务管理(即,用于)。LocalContainerEntityManagerFactoryBeanJpaVendorAdapterJpaDialectHibernateJpaVendorAdapterEclipseLinkJpaVendorAdapterEntityManagerFactoryJpaTransactionManager | 
请参阅 JpaDialect 和 JpaVendorAdapter javadoc 以获取
有关其操作的更多详细信息以及如何在 Spring 的 JPA 支持中使用它们。
作为一个更广泛的提供程序适配工具,主要针对 Spring 的全功能设置,它结合了
功能。指定 or 是最方便的
为 Hibernate 或 EclipseLink 自动配置设置的方式,
分别。请注意,这些提供程序适配器主要设计用于
Spring 驱动的事务管理(即,用于)。LocalContainerEntityManagerFactoryBeanJpaVendorAdapterJpaDialectHibernateJpaVendorAdapterEclipseLinkJpaVendorAdapterEntityManagerFactoryJpaTransactionManager | 
使用 JTA Transaction Management 设置 JPA
作为 的替代方法,Spring 还允许使用多资源
通过 JTA 进行事务协调,无论是在 Jakarta EE 环境中还是使用
独立的事务协调器,例如 Atomikos。除了选择 Spring's 而不是 之外,您还需要更进一步
步骤:JpaTransactionManagerJtaTransactionManagerJpaTransactionManager
- 
底层 JDBC 连接池需要支持 XA,并与 您的交易协调器。这在 Jakarta EE 环境中通常很简单。 通过 JNDI 公开不同类型的 。查看您的应用程序服务器 documentation 了解详细信息。类似地,独立的事务协调器通常 带有特殊的 XA 集成变体。同样,请查看其文档。
DataSourceDataSource - 
需要为 JTA 配置 JPA 设置。这是 特定于提供程序,通常通过特殊属性指定为 on 。在 Hibernate 的情况下,这些属性 甚至特定于版本。有关详细信息,请参阅 Hibernate 文档。
EntityManagerFactoryjpaPropertiesLocalContainerEntityManagerFactoryBean - 
Spring 强制执行某些面向 Spring 的默认值,例如 作为连接释放模式,它与 Hibernate 自己在 Hibernate 5.0 版本,但在 Hibernate 5.1+ 中不再运行。对于 JTA 设置,请确保声明 您的 Persistence Unit 事务类型为 “JTA”。或者,将 Hibernate 5.2 的属性设置为以恢复 Hibernate 自己的默认值。 有关相关说明,请参阅 Spurious Application Server Warnings with Hibernate。
HibernateJpaVendorAdapteron-closehibernate.connection.handling_modeDELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT - 
或者,考虑从您的应用程序中获取 server 本身(即,通过 JNDI 查找而不是 local declaration )。server-provided 可能需要在服务器配置中进行特殊定义(进行部署 不太可移植),但针对服务器的 JTA 环境进行了设置。
EntityManagerFactoryLocalContainerEntityManagerFactoryBeanEntityManagerFactory 
用于 JPA 交互的本机 Hibernate 设置和本机 Hibernate 事务
本机设置与 允许与其他 JPA 访问代码进行交互。Hibernate 现在原生实现了 JPA 的接口
Hibernate 句柄本身是 JPA 。
Spring 的 JPA 支持工具会自动检测本机 Hibernate 会话。LocalSessionFactoryBeanHibernateTransactionManager@PersistenceContextSessionFactoryEntityManagerFactorySessionEntityManager
因此,这种原生 Hibernate 设置可以替代标准 JPA 和组合
在许多情况下,允许与 (以及 ) 在 Within 之间进行交互
相同的本地事务。这样的设置还提供了更强的 Hibernate 集成
以及更大的配置灵活性,因为它不受 JPA 引导契约的约束。LocalContainerEntityManagerFactoryBeanJpaTransactionManagerSessionFactory.getCurrentSession()HibernateTemplate@PersistenceContext EntityManager
在这种情况下,您不需要配置,
因为 Spring 的原生 Hibernate 设置提供了更多功能
(例如,自定义 Hibernate Integrator 设置、Hibernate 5.3 Bean 容器集成、
以及对只读事务的更强优化)。最后但并非最不重要的一点是,您还可以
express native Hibernate 设置,通过 ,
与 style configuration 无缝集成(不涉及)。HibernateJpaVendorAdapterLocalSessionFactoryBuilder@BeanFactoryBean
| 
 
 在 上,这可以通过属性获得。在 programmatic 上,重载方法采用 bootstrap executor 参数。  | 
| 
 
 在 上,这可以通过属性获得。在 programmatic 上,重载方法采用 bootstrap executor 参数。  |