对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
JPA
该软件包下提供的 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:LocalEntityManagerFactoryBean
EntityManagerFactory
PersistenceProvider
<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.xml
persistence-unit-ref
web.xml
在这种情况下,整个持久化单元部署,包括编织
(字节码转换)的持久化类,则取决于 Jakarta EE 服务器。JDBC 是通过文件中的 JNDI 位置定义的。 事务与服务器的 JTA 子系统集成。仅 Spring
使用获取的 ,通过
持久性单元的依赖关系注入和管理事务(通常
通过 )。DataSource
META-INF/persistence.xml
EntityManager
EntityManagerFactory
JtaTransactionManager
如果在同一应用程序中使用多个持久性单元,则此类
JNDI 检索到的持久性单元应与
application 用于引用它们(例如,IN 和 Annotations)。@PersistenceUnit
@PersistenceContext
用LocalContainerEntityManagerFactoryBean
您可以在基于 Spring 的应用程序环境中使用此选项来获得完整的 JPA 功能。 这包括 Web 容器(如 Tomcat)、独立应用程序以及 具有复杂持久性要求的集成测试。
可以完全控制配置,适用于满足以下条件的环境
需要精细的自定义。将基于文件创建一个实例,
提供的策略和指定的 .因此,
可以在 JNDI 之外使用自定义数据源并控制编织
过程。以下示例显示了 a 的典型 bean 定义:LocalContainerEntityManagerFactoryBean
EntityManagerFactory
LocalContainerEntityManagerFactoryBean
PersistenceUnitInfo
persistence.xml
dataSourceLookup
loadTimeWeaver
LocalContainerEntityManagerFactoryBean
<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 的类加载器的可用性
字节码转换。LocalContainerEntityManagerFactoryBean
DataSource
此选项可能与 Jakarta EE 服务器的内置 JPA 功能冲突。在
完整的 Jakarta EE 环境,请考虑从 JNDI 获取您的环境。
或者,在定义中指定自定义(例如
META-INF/my-persistence.xml),并在
应用程序 jar 文件。由于 Jakarta EE 服务器仅查找默认文件,因此它会忽略此类自定义持久性单元,因此,
避免与 Spring 驱动的 JPA 预先设置冲突。(这适用于 Resin 3.1,用于
示例。EntityManagerFactory
persistenceXmlLocation
LocalContainerEntityManagerFactoryBean
META-INF/persistence.xml
该接口是 Spring 提供的类,它允许以特定方式插入 JPA 实例,具体取决于
environment 是 Web 容器或应用程序服务器。通过代理程序进行挂钩通常效率不高。代理针对整个虚拟机工作,并且
检查加载的每个类,这在生产中通常是不可取的
服务器环境。LoadTimeWeaver
ClassTransformer
ClassTransformers
Spring 为各种环境提供了许多实现,
让实例仅应用于每个类加载器,而不是
对于每个 VM。LoadTimeWeaver
ClassTransformer
请参阅 AOP 章节中的 Spring 配置
有关实施及其设置的更多见解
通用或针对各种平台(如 Tomcat、JBoss 和 WebSphere)进行定制。LoadTimeWeaver
如 Spring 配置中所述,您可以配置
使用 annotation 或 XML 元素进行上下文范围的调用。这样的全局 weaver 会自动被选中
按所有 JPA 实例。以下示例
显示设置加载时编织机的首选方法,提供自动检测
平台(例如 Tomcat 的具有 weaving 功能的类加载器或 Spring 的 JVM 代理)
以及将 Weaver 自动传播到所有可识别 Weaver 的 bean:LoadTimeWeaver
@EnableLoadTimeWeaving
context:load-time-weaver
LocalContainerEntityManagerFactoryBean
<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 检索。(默认情况下,类路径
将搜索文件。以下示例配置
多个地点:PersistenceUnitManager
META-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,则创建一个 .PersistenceUnitInfo
PersistenceUnitPostProcessor
PersistenceUnitManager
LocalContainerEntityManagerFactoryBean
后台引导
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,请确保还为其存储库设置延迟引导。EntityManagerFactory
EntityManagerFactoryInfo
createEntityManager
基于 JPA 实现 DAO:和EntityManagerFactory
EntityManager
尽管实例是线程安全的,但实例
不是。注入的 JPA 的行为类似于从
应用程序服务器的 JNDI 环境,如 JPA 规范所定义。它委派
对当前 transactional 的所有调用(如果有)。否则,它会回退
添加到新创建的 per 操作中,实际上使其使用线程安全。EntityManagerFactory EntityManager EntityManager EntityManager EntityManager EntityManager |
可以针对普通 JPA 编写代码,而没有任何 Spring 依赖项,方法是
使用注入的 或 .Spring 可以在字段和方法中理解 and 注解
level (如果启用了 a)。以下示例
显示了使用注解的普通 JPA DAO 实现:EntityManagerFactory
EntityManager
@PersistenceUnit
@PersistenceContext
PersistenceAnnotationBeanPostProcessor
@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) 用于基于注释的配置,包括 等。PersistenceAnnotationBeanPostProcessor
context:annotation-config
CommonAnnotationBeanPostProcessor
请考虑以下示例:
<beans>
<!-- post-processors for all standard config annotations -->
<context:annotation-config/>
<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
这种 DAO 的主要问题是它总是创建一个新的
工厂。您可以通过请求事务性(也称为
“shared EntityManager”,因为它是实际事务的共享线程安全代理
EntityManager) 而不是工厂。以下示例显示了如何执行此操作:EntityManager
EntityManager
-
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。只应该使用扩展实例
在有状态组件中,例如,驻留在会话中,其生命周期不与当前事务绑定,而是完全取决于
应用。@PersistenceContext
type
PersistenceContextType.TRANSACTION
EntityManager
PersistenceContextType.EXTENDED
EntityManager
EntityManager
EntityManager
注入的 is 由 Spring 管理的(知道正在进行的事务)。
即使新的 DAO 实现使用方法级注入 an 而不是 an ,也不需要更改 bean 定义
由于 Comments 的使用。EntityManager
EntityManager
EntityManagerFactory
这种 DAO 风格的主要优点是它仅依赖于 Java 持久性 API。 不需要导入任何 Spring 类。此外,正如 JPA 注释所理解的那样, 注入由 Spring 容器自动应用。这很吸引人 非侵入性视角,对于 JPA 开发人员来说可能感觉更自然。
基于实现 DAO(通常使用基于构造函数的注入)@Autowired
@PersistenceUnit
并且只能在方法和字段上声明。
通过构造函数和其他注入点提供 JPA 资源怎么样?@PersistenceContext
@Autowired
EntityManagerFactory
可以通过构造函数和字段/方法轻松注入
只要将目标定义为 bean,例如 via .
注入点按类型按原样匹配原始定义。@Autowired
LocalContainerEntityManagerFactoryBean
EntityManagerFactory
但是,-style 共享引用不适用于
开箱即用的常规依赖项注入。为了使其可用于基于类型的
根据需要进行匹配,考虑将 a 定义为
companion 的定义:@PersistenceContext
EntityManager
@Autowired
SharedEntityManagerBean
EntityManagerFactory
<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
@Bean("em")
public static EntityManager sharedEntityManager(EntityManagerFactory emf) {
return SharedEntityManagerCreator.createSharedEntityManager(emf);
}
如果有多个持久化单元,则每个定义都需要
伴随着相应的 bean 定义,最好带有限定符
与 distinct 定义匹配以区分
持久性单元通过 .EntityManagerFactory
EntityManager
EntityManagerFactory
@Autowired @Qualifier("…")
Spring 驱动的 JPA 事务
我们强烈建议您阅读声明式事务管理, 如果您还没有这样做,请更详细地了解 Spring 的声明式事务支持。 |
JPA 的推荐策略是通过 JPA 的本机事务进行本地事务处理
支持。Spring 提供了许多已知于本地
JDBC 事务(例如特定于事务的隔离级别和资源级别的
read-only optimizations) 针对任何常规 JDBC 连接池(无 XA 要求)。JpaTransactionManager
Spring JPA 还允许配置的 JPA 事务
添加到访问相同 的 JDBC 访问代码中,前提是已注册支持检索底层 JDBC 。
Spring 为 EclipseLink 和 Hibernate JPA 实现提供了方言。
有关机制的详细信息,请参阅下一节。JpaTransactionManager
DataSource
JpaDialect
Connection
JpaDialect
理解和JpaDialect
JpaVendorAdapter
作为高级功能, 和 子类 允许将自定义传递到 bean 属性中。实施可以启用以下高级
Spring 支持的功能,通常以特定于供应商的方式:JpaTransactionManager
AbstractEntityManagerFactoryBean
JpaDialect
jpaDialect
JpaDialect
-
应用特定的事务语义(例如自定义隔离级别或事务 超时)
-
检索事务性 JDBC(用于向基于 JDBC 的 DAO 公开)
Connection
-
到 Spring 的高级翻译
PersistenceException
DataAccessException
这对于特殊事务语义和高级
exception 的翻译。默认实现 () 会
不提供任何特殊功能,并且如果需要前面列出的功能,则您具有
以指定适当的方言。DefaultJpaDialect
作为一个更广泛的提供程序适配工具,主要针对 Spring 的全功能设置,它结合了
功能。指定 or 是最方便的
为 Hibernate 或 EclipseLink 自动配置设置的方式,
分别。请注意,这些提供程序适配器主要设计用于
Spring 驱动的事务管理(即,用于)。LocalContainerEntityManagerFactoryBean JpaVendorAdapter JpaDialect HibernateJpaVendorAdapter EclipseLinkJpaVendorAdapter EntityManagerFactory JpaTransactionManager |
请参阅 JpaDialect
和 JpaVendorAdapter
javadoc 以获取
有关其操作的更多详细信息以及如何在 Spring 的 JPA 支持中使用它们。
使用 JTA Transaction Management 设置 JPA
作为 的替代方法,Spring 还允许使用多资源
通过 JTA 进行事务协调,无论是在 Jakarta EE 环境中还是使用
独立的事务协调器,例如 Atomikos。除了选择 Spring's 而不是 之外,您还需要更进一步
步骤:JpaTransactionManager
JtaTransactionManager
JpaTransactionManager
-
底层 JDBC 连接池需要支持 XA,并与 您的交易协调器。这在 Jakarta EE 环境中通常很简单。 通过 JNDI 公开不同类型的 。查看您的应用程序服务器 documentation 了解详细信息。类似地,独立的事务协调器通常 带有特殊的 XA 集成变体。同样,请查看其文档。
DataSource
DataSource
-
需要为 JTA 配置 JPA 设置。这是 特定于提供程序,通常通过特殊属性指定为 on 。在 Hibernate 的情况下,这些属性 甚至特定于版本。有关详细信息,请参阅 Hibernate 文档。
EntityManagerFactory
jpaProperties
LocalContainerEntityManagerFactoryBean
-
Spring 强制执行某些面向 Spring 的默认值,例如 作为连接释放模式,它与 Hibernate 自己在 Hibernate 5.0 版本,但在 Hibernate 5.1+ 中不再运行。对于 JTA 设置,请确保声明 您的 Persistence Unit 事务类型为 “JTA”。或者,将 Hibernate 5.2 的属性设置为以恢复 Hibernate 自己的默认值。 有关相关说明,请参阅 Spurious Application Server Warnings with Hibernate。
HibernateJpaVendorAdapter
on-close
hibernate.connection.handling_mode
DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
-
或者,考虑从您的应用程序中获取 server 本身(即,通过 JNDI 查找而不是 local declaration )。server-provided 可能需要在服务器配置中进行特殊定义(进行部署 不太可移植),但针对服务器的 JTA 环境进行了设置。
EntityManagerFactory
LocalContainerEntityManagerFactoryBean
EntityManagerFactory
用于 JPA 交互的本机 Hibernate 设置和本机 Hibernate 事务
本机设置与 允许与其他 JPA 访问代码进行交互。Hibernate 现在原生实现了 JPA 的接口
Hibernate 句柄本身是 JPA 。
Spring 的 JPA 支持工具会自动检测本机 Hibernate 会话。LocalSessionFactoryBean
HibernateTransactionManager
@PersistenceContext
SessionFactory
EntityManagerFactory
Session
EntityManager
因此,这种原生 Hibernate 设置可以替代标准 JPA 和组合
在许多情况下,允许与 (以及 ) 在 Within 之间进行交互
相同的本地事务。这样的设置还提供了更强的 Hibernate 集成
以及更大的配置灵活性,因为它不受 JPA 引导契约的约束。LocalContainerEntityManagerFactoryBean
JpaTransactionManager
SessionFactory.getCurrentSession()
HibernateTemplate
@PersistenceContext EntityManager
在这种情况下,您不需要配置,
因为 Spring 的原生 Hibernate 设置提供了更多功能
(例如,自定义 Hibernate Integrator 设置、Hibernate 5.3 Bean 容器集成、
以及对只读事务的更强优化)。最后但并非最不重要的一点是,您还可以
express native Hibernate 设置,通过 ,
与 style configuration 无缝集成(不涉及)。HibernateJpaVendorAdapter
LocalSessionFactoryBuilder
@Bean
FactoryBean
在 上,这可以通过属性获得。在 programmatic 上,重载方法采用 bootstrap executor 参数。 |