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