软件包下提供的 Spring JPA 提供
对 Java 持久性的全面支持
API以类似于与Hibernate集成的方式,同时意识到
基础实现,以提供附加功能。org.springframework.orm.jpa
Spring 环境中 JPA 设置的三个选项
Spring 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 子系统集成。春天只是
使用获取的,通过
依赖关系注入和管理持久性单元的事务(通常
通过 )。DataSourceMETA-INF/persistence.xmlEntityManagerEntityManagerFactoryJtaTransactionManager
如果在同一应用程序中使用多个持久性单元,则此类 Bean 名称
JNDI 检索的持久性单元应与持久性单元名称匹配,并且
应用程序用于引用它们(例如,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 ,支持本地和全局事务,以及
依此类推。但是,它也会对运行时环境提出要求,例如
如果持久性提供程序需要,则提供具有编织功能的类加载器
字节码转换。LocalContainerEntityManagerFactoryBeanDataSource
此选项可能与 Jakarta EE 服务器的内置 JPA 功能冲突。在
完整的 Jakarta EE 环境,请考虑从 JNDI 获取您的环境。
或者,在定义中指定自定义项(例如,
META-INF/my-persistence.xml),并在
应用程序 jar 文件。由于 Jakarta EE 服务器仅查找默认文件,因此它会忽略此类自定义持久性单元,因此,
避免与 Spring 驱动的 JPA 预先设置发生冲突。(这适用于树脂 3.1,用于
示例。EntityManagerFactorypersistenceXmlLocationLocalContainerEntityManagerFactoryBeanMETA-INF/persistence.xml
该接口是 Spring 提供的类,它允许以特定方式插入 JPA 实例,具体取决于
环境是 Web 容器或应用程序服务器。通过代理挂钩通常效率不高。代理针对整个虚拟机和
检查加载的每个类,这在生产中通常是不可取的
服务器环境。LoadTimeWeaverClassTransformerClassTransformers
Spring 为各种环境提供了许多实现,
让实例只应用于每个类装入器,而不是
对于每个 VM。LoadTimeWeaverClassTransformer
请参阅 AOP 一章中的 Spring 配置,了解
有关实现及其设置的更多见解
通用或定制到各种平台(如 Tomcat、JBoss 和 WebSphere)。LoadTimeWeaver
如 Spring 配置中所述,您可以配置
使用注释或 XML 元素的上下文范围。这样的全球织布机会自动被捡起来
由所有 JPA 实例提供。以下示例
显示了设置加载时织布器的首选方法,提供自动检测
平台(例如 Tomcat 的 weaving-capable class loader 或 Spring 的 JVM 代理)
以及将织布机自动传播到所有具有织机意识的 Bean:LoadTimeWeaver@EnableLoadTimeWeavingcontext:load-time-weaverLocalContainerEntityManagerFactoryBean
<context:load-time-weaver/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>
但是,如果需要,可以通过属性手动指定专用的 weaver,如以下示例所示:loadTimeWeaver
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</property>
</bean>
无论 LTW 如何配置,通过使用这种技术,JPA 应用程序都依赖于 检测可以在目标平台(例如 Tomcat)中运行,而无需代理。 当托管应用程序依赖于不同的 JPA 时,这一点尤其重要 实现,因为 JPA 转换器只在类加载器级别应用,并且 因此,彼此隔离。
处理多个持久性单元
对于依赖于多个持久性单元位置(存储在
例如,类路径中的 JARS),Spring 提供了 to 充当
一个中央存储库,并避免持久性单元的发现过程,这可以是
贵。默认实现允许指定多个位置。这些位置是
分析,然后通过持久性单元名称进行检索。(默认情况下,类路径
搜索文件。以下示例配置
多个地点: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 提供程序
正在被其他组件访问(例如,调用),那些
调用块,直到后台引导完成。特别是,当您使用
Spring Data JPA,请确保为其存储库设置延迟引导。EntityManagerFactoryEntityManagerFactoryInfocreateEntityManager
实现基于 JPA 的 DAO: 和EntityManagerFactoryEntityManager
尽管实例是线程安全的,但实例
不是。注入的 JPA 的行为类似于从
应用程序服务器的 JNDI 环境,由 JPA 规范定义。它委托
对当前事务的所有调用(如果有)。否则,它会回退
到每个操作新创建的操作,实际上使其使用线程安全。EntityManagerFactoryEntityManagerEntityManagerEntityManagerEntityManagerEntityManager |
可以在没有任何 Spring 依赖项的情况下针对普通 JPA 编写代码,方法是
使用注入的 或 .Spring 可以理解字段和方法上的注释
级别(如果启用了 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 元素
上下文配置。这样做会自动注册所有 Spring 标准
用于基于注释的配置的后处理器,包括等。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
}
}
注解有一个名为 的可选属性,该属性默认为
自。您可以使用此默认值来接收共享代理。另一种选择是 , 完全
不同的事情。这导致了所谓的扩展,它不是
线程安全,因此不得在并发访问的组件中使用,例如
弹簧管理的单例豆。只应使用扩展实例
例如,在驻留在会话中的有状态组件中,其生命周期不与当前事务绑定,而是完全取决于
应用。@PersistenceContexttypePersistenceContextType.TRANSACTIONEntityManagerPersistenceContextType.EXTENDEDEntityManagerEntityManagerEntityManager
注入的是 Spring 管理的(知道正在进行的事务)。
尽管新的 DAO 实现使用方法级注入 an 而不是 ,但 Bean 定义中不需要更改
由于注释的使用。EntityManagerEntityManagerEntityManagerFactory
这种 DAO 风格的主要优点是它只依赖于 Java 持久性 API。 不需要导入任何 Spring 类。此外,正如对 JPA 注解的理解, 喷射由弹簧容器自动应用。这很吸引人 非侵入性视角,对 JPA 开发人员来说感觉更自然。
基于(通常使用基于构造函数的注入)实现 DAO(通常使用基于构造函数的注入)@Autowired
@PersistenceUnit并且只能在方法和字段上声明。
通过构造函数和其他注入点提供 JPA 资源怎么样?@PersistenceContext@Autowired
EntityManagerFactory可以通过构造函数和字段/方法轻松注入
只要将目标定义为 Bean,例如通过 .
注射点按原样按类型匹配原始定义。@AutowiredLocalContainerEntityManagerFactoryBeanEntityManagerFactory
但是,-style 共享引用不适用于
开箱即用的定期依赖注入。为了使其可用于基于类型的
根据 的要求进行匹配,考虑将 A 定义为
适合您的定义:@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 定义,最好带有限定符
与不同的定义相匹配,以便区分
持久性单元通过 .EntityManagerFactoryEntityManagerEntityManagerFactory@Autowired @Qualifier("…")
Spring 驱动的 JPA 事务
| 我们强烈建议您阅读声明式事务管理, 如果您还没有这样做,请更详细地了解 Spring 的声明式事务支持。 |
JPA 的推荐策略是通过 JPA 的本机事务进行本地事务
支持。Spring 提供了许多本地已知的功能
JDBC 事务(例如特定于事务的隔离级别和资源级别
只读优化)针对任何常规 JDBC 连接池,无需
JTA 事务协调器和支持 XA 的资源。JpaTransactionManager
Spring JPA 还允许配置的 JPA 事务公开
到访问相同的 JDBC 访问代码,前提是注册的 支持检索底层 JDBC 。Spring 提供
EclipseLink 和 Hibernate JPA 实现的方言。有关 的详细信息,请参阅下一节。JpaTransactionManagerDataSourceJpaDialectConnectionJpaDialect
对于实际资源连接的 JTA 式延迟检索,Spring 提供了
目标连接池的对应代理类:请参阅 LazyConnectionDataSourceProxy。
这对于 JPA 只读事务特别有用,因为 JPA 只读事务通常可以
从本地缓存进行处理,而不是访问数据库。DataSource
理解和JpaDialectJpaVendorAdapter
作为一项高级功能,子类 允许将自定义传递到 bean 属性中。实现可以启用以下高级
Spring 支持的功能,通常以特定于供应商的方式:JpaTransactionManagerAbstractEntityManagerFactoryBeanJpaDialectjpaDialectJpaDialect
-
应用特定的事务语义(例如自定义隔离级别或事务 超时)
-
检索事务性 JDBC(用于公开基于 JDBC 的 DAO)
Connection -
to Spring's 的高级翻译
PersistenceExceptionDataAccessException
这对于特殊事务语义和高级事务特别有价值
例外的翻译。默认实现 () 执行
不提供任何特殊能力,如果需要前面列出的功能,您有
以指定适当的方言。DefaultJpaDialect
作为一个更广泛的提供者适配工具,主要用于 Spring 的全功能设置,结合了
具有其他特定于提供程序的默认值的功能。指定 or 是最方便的
自动配置 Hibernate 或 EclipseLink 设置的方式,
分别。请注意,这些提供程序适配器主要设计用于
Spring 驱动的事务管理(即与 一起使用)。LocalContainerEntityManagerFactoryBeanJpaVendorAdapterJpaDialectHibernateJpaVendorAdapterEclipseLinkJpaVendorAdapterEntityManagerFactoryJpaTransactionManager |
请参阅 JpaDialect 和 JpaVendorAdapter javadoc
有关其操作的更多详细信息,以及如何在 Spring 的 JPA 支持中使用它们。
使用 JTA 事务管理设置 JPA
作为 的替代方案,Spring 还允许多资源
通过JTA进行交易协调,无论是在Jakarta EE环境中还是在Jakarta EE环境中
独立的事务协调器,如Atomikos。除了选择 Spring 而不是 之外,您还需要更进一步
步骤:JpaTransactionManagerJtaTransactionManagerJpaTransactionManager
-
底层 JDBC 连接池需要支持 XA 并集成 您的交易协调员。这在 Jakarta EE 环境中通常很简单, 通过JNDI暴露了另一种。查看您的应用程序服务器 文档了解详情。类似地,独立的事务协调器通常 带有特殊的 XA 集成变体。再次,检查其文档。
DataSourceDataSource -
需要为 JTA 配置 JPA 设置。这是 特定于提供程序,通常通过指定为 on 的特殊属性。在 Hibernate 的情况下,这些属性 甚至特定于版本。有关详细信息,请参阅 Hibernate 文档。
EntityManagerFactoryjpaPropertiesLocalContainerEntityManagerFactoryBean -
Spring 强制执行某些面向 Spring 的默认值,例如 作为连接释放模式,它与 Hibernate 自己的默认值相匹配 Hibernate 5.0,但在 Hibernate 5.1+ 中不再存在。对于 JTA 设置,请确保声明 持久性单元事务类型为“JTA”。或者,将 Hibernate 5.2 的属性设置为恢复 Hibernate 自己的默认值。 有关相关说明,请参阅使用 Hibernate 的虚假应用程序服务器警告。
HibernateJpaVendorAdapteron-closehibernate.connection.handling_modeDELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT -
或者,考虑从应用程序中获取 服务器本身(即,通过JNDI查找而不是本地声明)。服务器提供的服务器可能需要在服务器配置中进行特殊定义(使部署 不太便携),但已针对服务器的 JTA 环境进行设置。
EntityManagerFactoryLocalContainerEntityManagerFactoryBeanEntityManagerFactory
用于 JPA 交互的本机 Hibernate 设置和本机 Hibernate 事务
本机设置与 相结合,允许与其他 JPA 访问代码进行交互。Hibernate 现在原生实现了 JPA 的接口
而 Hibernate 句柄本身就是一个 JPA 。
Spring 的 JPA 支持工具会自动检测本机 Hibernate 会话。LocalSessionFactoryBeanHibernateTransactionManager@PersistenceContextSessionFactoryEntityManagerFactorySessionEntityManager
因此,这种原生 Hibernate 设置可以替代标准 JPA 和组合
在许多情况下,允许与(以及)在内部进行交互
相同的本地事务。这样的设置还提供了更强大的 Hibernate 集成
以及更大的配置灵活性,因为它不受 JPA 引导协定的约束。LocalContainerEntityManagerFactoryBeanJpaTransactionManagerSessionFactory.getCurrentSession()HibernateTemplate@PersistenceContext EntityManager
在这种情况下,您不需要配置,
因为 Spring 的原生 Hibernate 设置提供了更多功能
(例如,自定义 Hibernate Integrator 设置、Hibernate 5.3 Bean 容器集成、
以及针对只读事务的更强优化)。最后但并非最不重要的一点是,您还可以
通过表达原生 Hibernate 设置,
与样式配置无缝集成(不涉及)。HibernateJpaVendorAdapterLocalSessionFactoryBuilder@BeanFactoryBean
|
在 上,这可以通过酒店获得。在编程 上,重载方法采用引导执行器参数。 |