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