5. 对象关系映射(ORM)数据访问

预计阅读时间: 80 分钟

This section covers data access when you use Object Relational Mapping (ORM).
本节涵盖使用对象关系映射(ORM)进行数据访问的内容。

(#orm-introduction)5.1. Introduction to ORM with Spring

5.1. Spring ORM 简介

The Spring Framework supports integration with the Java Persistence API (JPA) and supports native Hibernate for resource management, data access object (DAO) implementations, and transaction strategies.
Spring 框架支持与 Java 持久化 API(JPA)的集成,并支持原生 Hibernate 进行资源管理、数据访问对象(DAO)实现和事务策略。
For example, for Hibernate, there is first-class support with several convenient IoC features that address many typical Hibernate integration issues. You can configure all of the supported features for OR (object relational) mapping tools through Dependency Injection.
例如,对于 Hibernate,它提供了第一级支持,包括几个方便的 IoC 特性,这些特性解决了许多典型的 Hibernate 集成问题。您可以通过依赖注入配置所有支持的对象关系(OR)映射工具的特性。
They can participate in Spring’s resource and transaction management, and they comply with Spring’s generic transaction and DAO exception hierarchies. The recommended integration style is to code DAOs against plain Hibernate or JPA APIs.
它们可以参与 Spring 的资源管理和事务管理,并且它们遵循 Spring 的通用事务和 DAO 异常层次结构。推荐的集成方式是对 DAO 进行编码,以使用纯 Hibernate 或 JPA API。

Spring adds significant enhancements to the ORM layer of your choice when you create data access applications.
Spring 在创建数据访问应用程序时,为您选择的 ORM 层添加了显著的增强功能。
You can leverage as much of the integration support as you wish, and you should compare this integration effort with the cost and risk of building a similar infrastructure in-house.
您可以充分利用您想要的任何集成支持,并且您应该将这项集成工作与内部构建类似基础设施的成本和风险进行比较。
You can use much of the ORM support as you would a library, regardless of technology, because everything is designed as a set of reusable JavaBeans. ORM in a Spring IoC container facilitates configuration and deployment.
您可以将大部分 ORM 支持当作库来使用,无论技术如何,因为一切都被设计成一组可重用的 JavaBeans。Spring IoC 容器中的 ORM 简化了配置和部署。
Thus, most examples in this section show configuration inside a Spring container.
因此,本节中的大多数示例都展示了 Spring 容器内部的配置。

The benefits of using the Spring Framework to create your ORM DAOs include:
使用 Spring 框架创建 ORM DAOs 的好处包括:

  • Easier testing. Spring’s IoC approach makes it easy to swap the implementations and configuration locations of Hibernate SessionFactory instances, JDBC DataSource instances, transaction managers, and mapped object implementations (if needed). This in turn makes it much easier to test each piece of persistence-related code in isolation.
    更简单的测试。Spring 的 IoC 方法使得交换 Hibernate SessionFactory 实现和配置位置、JDBC DataSource 实例、事务管理器和映射对象实现(如有需要)变得容易。这反过来使得单独测试每个持久性相关代码片段变得更加容易。

  • Common data access exceptions. Spring can wrap exceptions from your ORM tool, converting them from proprietary ( potentially checked) exceptions to a common runtime DataAccessException hierarchy. This feature lets you handle most persistence exceptions, which are non-recoverable, only in the appropriate layers, without annoying boilerplate catches, throws, and exception declarations. You can still trap and handle exceptions as necessary.
    常见数据访问异常。Spring 可以封装来自您的 ORM 工具的异常,将它们从专有(可能已检查)异常转换为通用的运行时 DataAccessException 层次。此功能允许您在适当的层中处理大多数持久性异常,这些异常是不可恢复的,无需烦人的样板代码捕获、抛出和异常声明。您仍然可以根据需要捕获和处理异常。
    Remember that JDBC exceptions (including DB-specific dialects) are also converted to the same hierarchy, meaning that you can perform some operations with JDBC within a consistent programming model.
    请记住,JDBC 异常(包括数据库特定的方言)也被转换为相同的层次结构,这意味着您可以在一致的编程模型中使用 JDBC 执行一些操作。

  • General resource management. Spring application contexts can handle the location and configuration of Hibernate SessionFactory instances, JPA EntityManagerFactory instances, JDBC DataSource instances, and other related resources. This makes these values easy to manage and change. Spring offers efficient, easy, and safe handling of persistence resources. For example, related code that uses Hibernate generally needs to use the same Hibernate Session to ensure efficiency and proper transaction handling. Spring makes it easy to create and bind a Session to the current thread transparently, by exposing a current Session through the Hibernate SessionFactory. Thus, Spring solves many chronic problems of typical Hibernate usage, for any local or JTA transaction environment.
    通用资源管理。Spring 应用程序上下文可以处理 Hibernate SessionFactory 实例、JPA EntityManagerFactory 实例、JDBC DataSource 实例和其他相关资源的定位和配置。这使得这些值易于管理和更改。Spring 提供了高效、简单、安全的持久化资源处理。例如,通常使用 Hibernate 的相关代码需要使用相同的 Hibernate Session 以确保效率和适当的交易处理。Spring 通过暴露 Hibernate SessionFactory 中的当前 Session ,使创建和绑定 Session 到当前线程变得简单,从而解决了典型 Hibernate 使用中的许多长期问题,适用于任何本地或 JTA 事务环境。

  • Integrated transaction management. You can wrap your ORM code with a declarative, aspect-oriented programming ( AOP) style method interceptor either through the @Transactional annotation or by explicitly configuring the transaction AOP advice in an XML configuration file. In both cases, transaction semantics and exception handling ( rollback and so on) are handled for you. As discussed in Resource and Transaction Management, you can also swap various transaction managers, without affecting your ORM-related code. For example, you can swap between local transactions and JTA, with the same full services (such as declarative transactions) available in both scenarios.
    集成事务管理。您可以通过 @Transactional 注解或通过在 XML 配置文件中显式配置事务 AOP 建议来使用声明式、面向切面编程(AOP)风格的方法拦截器包装您的 ORM 代码。在两种情况下,事务语义和异常处理(回滚等)都由您处理。如资源与事务管理中所述,您还可以交换各种事务管理器,而不会影响您的 ORM 相关代码。例如,您可以在本地事务和 JTA 之间进行交换,两种情况下都提供完整的服务(如声明式事务)。
    Additionally, JDBC-related code can fully integrate transactionally with the code you use to do ORM. This is useful for data access that is not suitable for ORM (such as batch processing and BLOB streaming) but that still needs to share common transactions with ORM operations.
    此外,与 JDBC 相关的代码可以与您用于 ORM 的代码完全集成进行事务处理。这对于不适合 ORM 的数据访问(如批量处理和 BLOB 流式传输)但仍需要与 ORM 操作共享事务非常有用。

For more comprehensive ORM support, including support for alternative database technologies such as MongoDB, you might want to check out the Spring Data suite of projects. If you are a JPA user, the Getting Started Accessing Data with JPA guide from https://spring.io provides a great introduction.
为了更全面的 ORM 支持,包括对 MongoDB 等替代数据库技术的支持,您可能想查看 Spring Data 项目套件。如果您是 JPA 用户,https://spring.io 上的“使用 JPA 访问数据入门指南”提供了一个很好的介绍。

(#orm-general)5.2. General ORM Integration Considerations

5.2. 通用 ORM 集成注意事项

This section highlights considerations that apply to all ORM technologies. The Hibernate section provides more details and also show these features and configurations in a concrete context.
本节强调了适用于所有 ORM 技术的考虑因素。Hibernate 部分提供了更多细节,并在具体上下文中展示了这些特性和配置。

The major goal of Spring’s ORM integration is clear application layering (with any data access and transaction technology) and for loose coupling of application objects — no more business service dependencies on the data access or transaction strategy, no more hard-coded resource lookups, no more hard-to-replace singletons, no more custom service registries.
Spring 的 ORM 集成的主要目标是清晰的应用层划分(与任何数据访问和事务技术)以及应用对象的松耦合——不再有业务服务对数据访问或事务策略的依赖,不再有硬编码的资源查找,不再有难以替换的单例,不再有自定义服务注册。
The goal is to have one simple and consistent approach to wiring up application objects, keeping them as reusable and free from container dependencies as possible.
目标是采用一种简单且一致的方法来连接应用程序对象,尽可能使它们具有可重用性,并摆脱容器依赖。
All the individual data access features are usable on their own but integrate nicely with Spring’s application context concept, providing XML-based configuration and cross-referencing of plain JavaBean instances that need not be Spring-aware.
所有单个数据访问功能都可以独立使用,但与 Spring 的应用上下文概念很好地集成,提供基于 XML 的配置和需要但不一定需要 Spring 意识的普通 JavaBean 实例的交叉引用。
In a typical Spring application, many important objects are JavaBeans: data access templates, data access objects, transaction managers, business services that use the data access objects and transaction managers, web view resolvers, web controllers that use the business services, and so on.
在一个典型的 Spring 应用程序中,许多重要对象都是 JavaBeans:数据访问模板、数据访问对象、事务管理器、使用数据访问对象和事务管理器的业务服务、视图解析器、使用业务服务的 Web 控制器等等。

(#orm-resource-mngmnt)5.2.1. Resource and Transaction Management

5.2.1. 资源和事务管理

Typical business applications are cluttered with repetitive resource management code. Many projects try to invent their own solutions, sometimes sacrificing proper handling of failures for programming convenience.
典型的商业应用程序充斥着重复的资源管理代码。许多项目试图发明自己的解决方案,有时为了编程方便而牺牲了对失败的适当处理。
Spring advocates simple solutions for proper resource handling, namely IoC through templating in the case of JDBC and applying AOP interceptors for the ORM technologies.
Spring 主张通过模板实现 IoC 以合理处理资源,在 JDBC 的情况下,以及应用 AOP 拦截器于 ORM 技术。

The infrastructure provides proper resource handling and appropriate conversion of specific API exceptions to an unchecked infrastructure exception hierarchy. Spring introduces a DAO exception hierarchy, applicable to any data access strategy. For direct JDBC, the JdbcTemplate class mentioned in a previous section provides connection handling and proper conversion of SQLException to the DataAccessException hierarchy, including translation of database-specific SQL error codes to meaningful exception classes. For ORM technologies, see the next section for how to get the same exception translation benefits.
该基础设施提供适当的资源处理和将特定 API 异常转换为未检查的基础设施异常层次结构的适当转换。Spring 引入了一个 DAO 异常层次结构,适用于任何数据访问策略。对于直接 JDBC,前一个部分中提到的 JdbcTemplate 类提供连接处理和将 SQLException 转换为 DataAccessException 层次结构的适当转换,包括将数据库特定的 SQL 错误代码转换为有意义的异常类。对于 ORM 技术,请参阅下一节了解如何获得相同的异常转换优势。

When it comes to transaction management, the JdbcTemplate class hooks in to the Spring transaction support and supports both JTA and JDBC transactions, through respective Spring transaction managers.
当涉及到事务管理时, JdbcTemplate 类通过 Spring 事务支持进行钩子操作,并通过各自的 Spring 事务管理器支持 JTA 和 JDBC 事务。
For the supported ORM technologies, Spring offers Hibernate and JPA support through the Hibernate and JPA transaction managers as well as JTA support. For details on transaction support, see the Transaction Management chapter.
对于支持的 ORM 技术,Spring 通过 Hibernate 和 JPA 事务管理器以及 JTA 支持提供 Hibernate 和 JPA 支持。有关事务支持的详细信息,请参阅事务管理章节。

(#orm-exception-translation)5.2.2. Exception Translation

5.2.2. 异常翻译

When you use Hibernate or JPA in a DAO, you must decide how to handle the persistence technology’s native exception classes. The DAO throws a subclass of a HibernateException or PersistenceException, depending on the technology. These exceptions are all runtime exceptions and do not have to be declared or caught. You may also have to deal with IllegalArgumentException and IllegalStateException. This means that callers can only treat exceptions as being generally fatal, unless they want to depend on the persistence technology’s own exception structure.
当你在 DAO 中使用 Hibernate 或 JPA 时,你必须决定如何处理持久化技术的本地异常类。DAO 会抛出一个 HibernateExceptionPersistenceException 的子类,具体取决于技术。这些异常都是运行时异常,无需声明或捕获。你可能还必须处理 IllegalArgumentExceptionIllegalStateException 。这意味着调用者只能将异常视为一般性的致命错误,除非他们想依赖持久化技术的自身异常结构。
Catching specific causes (such as an optimistic locking failure) is not possible without tying the caller to the implementation strategy. This trade-off might be acceptable to applications that are strongly ORM-based or do not need any special exception treatment (or both).
捕获特定原因(如乐观锁定失败)不可能,除非将调用者绑定到实现策略。这种权衡可能对基于 ORM 的应用程序或不需要任何特殊异常处理的应用程序(或两者都是)是可以接受的。
However, Spring lets exception translation be applied transparently through the @Repository annotation. The following examples (one for Java configuration and one for XML configuration) show how to do so:
然而,Spring 允许通过 @Repository 注解透明地应用异常转换。以下示例(一个用于 Java 配置,一个用于 XML 配置)展示了如何实现:

@Repository public class ProductDaoImpl implements ProductDao { // class body here... }
@Repository class ProductDaoImpl : ProductDao { // class body here... }
<beans> <!-- Exception translation bean post processor --> <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> <bean id="myProductDao" class="product.ProductDaoImpl"/> </beans>

The postprocessor automatically looks for all exception translators (implementations of the PersistenceExceptionTranslator interface) and advises all beans marked with the @Repository annotation so that the discovered translators can intercept and apply the appropriate translation on the thrown exceptions.
后处理器自动查找所有异常转换器( PersistenceExceptionTranslator 接口的实现)并通知所有带有 @Repository 注解的 bean,以便发现的转换器可以拦截并应用适当的转换到抛出的异常上。

In summary, you can implement DAOs based on the plain persistence technology’s API and annotations while still benefiting from Spring-managed transactions, dependency injection, and transparent exception conversion (if desired) to Spring’s custom exception hierarchies.
总结来说,您可以在使用纯持久化技术的 API 和注解实现 DAOs 的同时,仍然享受 Spring 管理的交易、依赖注入以及可选的透明异常转换(如果需要)到 Spring 的自定义异常层次结构。

(#orm-hibernate)5.3. Hibernate 5.3. Hibernate Hibernate

We start with a coverage of Hibernate 5 in a Spring environment, using it to demonstrate the approach that Spring takes towards integrating OR mappers. This section covers many issues in detail and shows different variations of DAO implementations and transaction demarcation.
我们从 Spring 环境中 Hibernate 5 的覆盖开始,用它来展示 Spring 在集成对象关系映射器方面的方法。本节详细介绍了许多问题,并展示了 DAO 实现和事务划分的不同变体。
Most of these patterns can be directly translated to all other supported ORM tools. The later sections in this chapter then cover the other ORM technologies and show brief examples.
大多数这些模式可以直接翻译到所有其他支持的 ORM 工具中。本章后面的部分将涵盖其他 ORM 技术并展示简要示例。

As of Spring Framework 5.3, Spring requires Hibernate ORM 5.2+ for Spring’s HibernateJpaVendorAdapter as well as for a native Hibernate SessionFactory setup. It is strongly recommended to go with Hibernate ORM 5.4 for a newly started application. For use with HibernateJpaVendorAdapter, Hibernate Search needs to be upgraded to 5.11.6.
截至 Spring Framework 5.3,Spring 需要 Hibernate ORM 5.2+以支持 Spring 的 HibernateJpaVendorAdapter ,以及原生 Hibernate SessionFactory 设置。强烈建议对于新启动的应用程序使用 Hibernate ORM 5.4。对于 HibernateJpaVendorAdapter 的使用,Hibernate Search 需要升级到 5.11.6。

(#orm-session-factory-setup)5.3.1.SessionFactory Setup in a Spring Container

5.3.1. SessionFactory 在 Spring 容器中设置

To avoid tying application objects to hard-coded resource lookups, you can define resources (such as a JDBC DataSource or a Hibernate SessionFactory) as beans in the Spring container. Application objects that need to access resources receive references to such predefined instances through bean references, as illustrated in the DAO definition in the next section.
为了避免将应用程序对象绑定到硬编码的资源查找,您可以在 Spring 容器中将资源(如 JDBC DataSource 或 Hibernate SessionFactory )定义为 bean。需要访问资源的应用程序对象通过 bean 引用接收这些预定义实例的引用,如下一节中的 DAO 定义所示。

The following excerpt from an XML application context definition shows how to set up a JDBC DataSource and a Hibernate SessionFactory on top of it:
以下是从 XML 应用程序上下文定义中摘录的内容,展示了如何在上面设置 JDBC DataSource 和 Hibernate SessionFactory

<beans> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="mappingResources"> <list> <value>product.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect </value> </property> </bean> </beans>

Switching from a local Jakarta Commons DBCP BasicDataSource to a JNDI-located DataSource (usually managed by an application server) is only a matter of configuration, as the following example shows:
从本地 Jakarta Commons DBCP BasicDataSource 切换到 JNDI 定位的 DataSource (通常由应用服务器管理)只需配置即可,以下示例显示:

<beans> <jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/> </beans>

You can also access a JNDI-located SessionFactory, using Spring’s JndiObjectFactoryBean / <jee:jndi-lookup> to retrieve and expose it. However, that is typically not common outside of an EJB context.
您还可以通过 Spring 的 JndiObjectFactoryBean / <jee:jndi-lookup> 访问 JNDI 定位的 SessionFactory ,但通常这不在 EJB 上下文中常见。

Spring also provides a LocalSessionFactoryBuilder variant, seamlessly integrating with @Bean style configuration and programmatic setup (no FactoryBean involved).
春季还提供了一种 LocalSessionFactoryBuilder 变体,与 @Bean 风格配置和程序设置无缝集成(不涉及 FactoryBean )。

Both LocalSessionFactoryBean and LocalSessionFactoryBuilder support background bootstrapping, with Hibernate initialization running in parallel to the application bootstrap thread on a given bootstrap executor (such as a SimpleAsyncTaskExecutor). On LocalSessionFactoryBean, this is available through the bootstrapExecutor property. On the programmatic LocalSessionFactoryBuilder, there is an overloaded buildSessionFactory method that takes a bootstrap executor argument.
两者都支持后台引导,Hibernate 初始化与给定引导执行器(如 SimpleAsyncTaskExecutor )上的应用程序引导线程并行运行。在 LocalSessionFactoryBean 上,这可以通过 bootstrapExecutor 属性实现。在程序性 LocalSessionFactoryBuilder 中,有一个重载的 buildSessionFactory 方法,该方法接受一个引导执行器参数。

As of Spring Framework 5.1, such a native Hibernate setup can also expose a JPA EntityManagerFactory for standard JPA interaction next to native Hibernate access. See Native Hibernate Setup for JPA for details.
截至 Spring Framework 5.1,这样的原生 Hibernate 设置也可以在原生 Hibernate 访问旁边暴露一个 JPA EntityManagerFactory 以进行标准 JPA 交互。有关详细信息,请参阅原生 Hibernate 设置中的 JPA。

(#orm-hibernate-straight)5.3.2. Implementing DAOs Based on the Plain Hibernate API

5.3.2. 基于普通 Hibernate API 实现 DAOs

Hibernate has a feature called contextual sessions, wherein Hibernate itself manages one current Session per transaction. This is roughly equivalent to Spring’s synchronization of one Hibernate Session per transaction. A corresponding DAO implementation resembles the following example, based on the plain Hibernate API:
Hibernate 有一个名为上下文会话的功能,其中 Hibernate 本身管理每个事务的一个当前 Session 。这大致相当于 Spring 对每个事务中一个 Hibernate Session 的同步。相应的 DAO 实现类似于以下示例,基于纯 Hibernate API:

public class ProductDaoImpl implements ProductDao { private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public Collection loadProductsByCategory(String category) { return this.sessionFactory.getCurrentSession() .createQuery("from test.Product product where product.category=?") .setParameter(0, category) .list(); } }
class ProductDaoImpl(private val sessionFactory: SessionFactory) : ProductDao { fun loadProductsByCategory(category: String): Collection<*> { return sessionFactory.currentSession .createQuery("from test.Product product where product.category=?") .setParameter(0, category) .list() } }

This style is similar to that of the Hibernate reference documentation and examples, except for holding the SessionFactory in an instance variable. We strongly recommend such an instance-based setup over the old-school static HibernateUtil class from Hibernate’s CaveatEmptor sample application. (In general, do not keep any resources in static variables unless absolutely necessary.)
这种风格类似于 Hibernate 参考文档和示例的风格,除了将 SessionFactory 存储在实例变量中。我们强烈推荐使用这种基于实例的设置,而不是 Hibernate 的 CaveatEmptor 示例应用程序中的老式 static HibernateUtil 类。(一般来说,除非绝对必要,否则不要在 static 变量中保留任何资源。)

The preceding DAO example follows the dependency injection pattern. It fits nicely into a Spring IoC container, as it would if coded against Spring’s HibernateTemplate. You can also set up such a DAO in plain Java (for example, in unit tests). To do so, instantiate it and call setSessionFactory(..) with the desired factory reference. As a Spring bean definition, the DAO would resemble the following:
前一个 DAO 示例遵循依赖注入模式。它很好地适应了 Spring IoC 容器,就像它针对 Spring 的 HibernateTemplate 编码一样。您还可以用纯 Java(例如,在单元测试中)设置这样的 DAO。为此,实例化它并使用所需的工厂引用调用 setSessionFactory(..) 。作为一个 Spring Bean 定义,DAO 将类似于以下内容:

<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> </beans>

The main advantage of this DAO style is that it depends on Hibernate API only. No import of any Spring class is required. This is appealing from a non-invasiveness perspective and may feel more natural to Hibernate developers.
这种 DAO 风格的优点主要是它仅依赖于 Hibernate API。无需导入任何 Spring 类。从非侵入性角度来看,这可能对 Hibernate 开发者来说更加自然。

However, the DAO throws plain HibernateException (which is unchecked, so it does not have to be declared or caught), which means that callers can treat exceptions only as being generally fatal — unless they want to depend on Hibernate’s own exception hierarchy.
然而,DAO 抛出 plain HibernateException (未经检查,因此无需声明或捕获),这意味着调用者只能将异常视为一般致命——除非他们想依赖 Hibernate 的异常层次结构。
Catching specific causes (such as an optimistic locking failure) is not possible without tying the caller to the implementation strategy. This trade off might be acceptable to applications that are strongly Hibernate-based, do not need any special exception treatment, or both.
捕获特定原因(如乐观锁定失败)无法在不将调用者绑定到实现策略的情况下实现。这种权衡可能对基于 Hibernate 的应用程序是可接受的,这些应用程序不需要任何特殊的异常处理,或者两者都是。

Fortunately, Spring’s LocalSessionFactoryBean supports Hibernate’s SessionFactory.getCurrentSession() method for any Spring transaction strategy, returning the current Spring-managed transactional Session, even with HibernateTransactionManager. The standard behavior of that method remains to return the current Session associated with the ongoing JTA transaction, if any. This behavior applies regardless of whether you use Spring’s JtaTransactionManager, EJB container managed transactions (CMTs), or JTA.
幸运的是,Spring 的 LocalSessionFactoryBean 支持 Hibernate 的 SessionFactory.getCurrentSession() 方法,适用于任何 Spring 事务策略,即使返回当前 Spring 管理的 Session ,即使有 HibernateTransactionManager 。该方法的标准化行为仍然是返回与当前进行的 JTA 事务关联的当前 Session ,如果有。此行为适用于您使用 Spring 的 JtaTransactionManager 、EJB 容器管理的事务(CMT)或 JTA 的情况。

In summary, you can implement DAOs based on the plain Hibernate API, while still being able to participate in Spring-managed transactions.
总结来说,您可以在不参与 Spring 管理的交易的情况下,基于纯 Hibernate API 实现 DAOs。

(#orm-hibernate-tx-declarative)5.3.3. Declarative Transaction Demarcation

5.3.3. 声明式事务界定

We recommend that you use Spring’s declarative transaction support, which lets you replace explicit transaction demarcation API calls in your Java code with an AOP transaction interceptor.
我们建议您使用 Spring 的声明式事务支持,这允许您用 AOP 事务拦截器替换 Java 代码中的显式事务边界 API 调用。
You can configure this transaction interceptor in a Spring container by using either Java annotations or XML.
您可以通过使用 Java 注解或 XML 在 Spring 容器中配置此事务拦截器。
This declarative transaction capability lets you keep business services free of repetitive transaction demarcation code and focus on adding business logic, which is the real value of your application.
这种声明性事务能力让您能够使业务服务免于重复的事务边界代码,并专注于添加业务逻辑,这是您应用程序的真实价值所在。

Before you continue, we are strongly encourage you to read Declarative Transaction Management if you have not already done so.
在您继续之前,我们强烈建议您如果尚未阅读,请阅读《声明式事务管理》。

You can annotate the service layer with @Transactional annotations and instruct the Spring container to find these annotations and provide transactional semantics for these annotated methods. The following example shows how to do so:
您可以使用 @Transactional 注解来注释服务层,并指导 Spring 容器查找这些注解,为这些注解的方法提供事务语义。以下示例展示了如何操作:

public class ProductServiceImpl implements ProductService { private ProductDao productDao; public void setProductDao(ProductDao productDao) { this.productDao = productDao; } @Transactional public void increasePriceOfAllProductsInCategory(final String category) { List productsToChange = this.productDao.loadProductsByCategory(category); // ... } @Transactional(readOnly = true) public List<Product> findAllProducts() { return this.productDao.findAllProducts(); } }
class ProductServiceImpl(private val productDao: ProductDao) : ProductService { @Transactional fun increasePriceOfAllProductsInCategory(category: String) { val productsToChange = productDao.loadProductsByCategory(category) // ... } @Transactional(readOnly = true) fun findAllProducts() = productDao.findAllProducts() }

In the container, you need to set up the PlatformTransactionManager implementation (as a bean) and a <tx:annotation-driven/> entry, opting into @Transactional processing at runtime. The following example shows how to do so:
在容器中,您需要设置 PlatformTransactionManager 实现(作为一个 bean)和一个 <tx:annotation-driven/> 条目,并在运行时选择启用 @Transactional 处理。以下示例展示了如何操作:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- SessionFactory, DataSource, etc. omitted --> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <tx:annotation-driven/> <bean id="myProductService" class="product.SimpleProductService"> <property name="productDao" ref="myProductDao"/> </bean> </beans>

(#orm-hibernate-tx-programmatic)5.3.4. Programmatic Transaction Demarcation

5.3.4. 程序性事务划分

You can demarcate transactions in a higher level of the application, on top of lower-level data access services that span any number of operations. Nor do restrictions exist on the implementation of the surrounding business service. It needs only a Spring PlatformTransactionManager. Again, the latter can come from anywhere, but preferably as a bean reference through a setTransactionManager(..) method. Also, the productDAO should be set by a setProductDao(..) method. The following pair of snippets show a transaction manager and a business service definition in a Spring application context and an example for a business method implementation:
您可以在应用的高级层中划分事务,在跨越任意数量操作的底层数据访问服务之上。周围业务服务的实现也没有限制。只需要一个 Spring PlatformTransactionManager 。再次强调,后者可以来自任何地方,但最好是作为一个通过 setTransactionManager(..) 方法的 bean 引用。此外, productDAO 应由 setProductDao(..) 方法设置。以下两个代码片段展示了 Spring 应用上下文中的一个事务管理器和业务服务定义,以及一个业务方法实现的示例:

<beans> <bean id="myTxManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> <bean id="myProductService" class="product.ProductServiceImpl"> <property name="transactionManager" ref="myTxManager"/> <property name="productDao" ref="myProductDao"/> </bean> </beans>
public class ProductServiceImpl implements ProductService { private TransactionTemplate transactionTemplate; private ProductDao productDao; public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionTemplate = new TransactionTemplate(transactionManager); } public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void increasePriceOfAllProductsInCategory(final String category) { this.transactionTemplate.execute(new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(TransactionStatus status) { List productsToChange = this.productDao.loadProductsByCategory(category); // do the price increase... } }); } }
class ProductServiceImpl(transactionManager: PlatformTransactionManager, private val productDao: ProductDao) : ProductService { private val transactionTemplate = TransactionTemplate(transactionManager) fun increasePriceOfAllProductsInCategory(category: String) { transactionTemplate.execute { val productsToChange = productDao.loadProductsByCategory(category) // do the price increase... } } }

Spring’s TransactionInterceptor lets any checked application exception be thrown with the callback code, while TransactionTemplate is restricted to unchecked exceptions within the callback. TransactionTemplate triggers a rollback in case of an unchecked application exception or if the transaction is marked rollback-only by the application (by setting TransactionStatus). By default, TransactionInterceptor behaves the same way but allows configurable rollback policies per method.
春季的 TransactionInterceptor 允许任何检查的应用程序异常通过回调代码抛出,而 TransactionTemplate 仅限于回调内的未检查异常。 TransactionTemplate 在发生未检查的应用程序异常或应用程序(通过设置 TransactionStatus )将事务标记为仅回滚时触发回滚。默认情况下, TransactionInterceptor 的行为相同,但允许每个方法配置可定制的回滚策略。

(#orm-hibernate-tx-strategies)5.3.5. Transaction Management Strategies

5.3.5. 事务管理策略

Both TransactionTemplate and TransactionInterceptor delegate the actual transaction handling to a PlatformTransactionManager instance (which can be a HibernateTransactionManager (for a single Hibernate SessionFactory) by using a ThreadLocal Session under the hood) or a JtaTransactionManager (delegating to the JTA subsystem of the container) for Hibernate applications. You can even use a custom PlatformTransactionManager implementation. Switching from native Hibernate transaction management to JTA (such as when facing distributed transaction requirements for certain deployments of your application) is only a matter of configuration.
两者 TransactionTemplateTransactionInterceptor 都将实际事务处理委托给一个 PlatformTransactionManager 实例(这可以是一个 HibernateTransactionManager (对于单个 Hibernate SessionFactory )通过使用底层的 ThreadLocal Session )或一个 JtaTransactionManager (委托给容器的 JTA 子系统)用于 Hibernate 应用程序。您甚至可以使用自定义的 PlatformTransactionManager 实现。从原生 Hibernate 事务管理切换到 JTA(例如,当面对应用程序某些部署的分布式事务需求时)只需配置即可。
You can replace the Hibernate transaction manager with Spring’s JTA transaction implementation. Both transaction demarcation and data access code work without changes, because they use the generic transaction management APIs.
您可以将 Hibernate 事务管理器替换为 Spring 的 JTA 事务实现。由于它们使用通用的交易管理 API,因此事务界定和数据访问代码无需更改即可正常工作。

For distributed transactions across multiple Hibernate session factories, you can combine JtaTransactionManager as a transaction strategy with multiple LocalSessionFactoryBean definitions. Each DAO then gets one specific SessionFactory reference passed into its corresponding bean property. If all underlying JDBC data sources are transactional container ones, a business service can demarcate transactions across any number of DAOs and any number of session factories without special regard, as long as it uses JtaTransactionManager as the strategy.
对于跨多个 Hibernate 会话工厂的分布式事务,您可以将 JtaTransactionManager 作为事务策略与多个 LocalSessionFactoryBean 定义结合使用。然后,每个 DAO 都会接收到一个特定的 SessionFactory 引用,传递到其对应的 bean 属性中。如果所有底层 JDBC 数据源都是事务容器型,那么业务服务可以在任何数量的 DAO 和任何数量的会话工厂上划分事务,无需特别关注,只要它使用 JtaTransactionManager 作为策略即可。

Both HibernateTransactionManager and JtaTransactionManager allow for proper JVM-level cache handling with Hibernate, without container-specific transaction manager lookup or a JCA connector (if you do not use EJB to initiate transactions).
两者 HibernateTransactionManagerJtaTransactionManager 都允许在 Hibernate 中进行适当的 JVM 级别缓存处理,无需查找容器特定的事务管理器或 JCA 连接器(如果您不使用 EJB 来启动事务)。

HibernateTransactionManager can export the Hibernate JDBC Connection to plain JDBC access code for a specific DataSource. This ability allows for high-level transaction demarcation with mixed Hibernate and JDBC data access completely without JTA, provided you access only one database. HibernateTransactionManager automatically exposes the Hibernate transaction as a JDBC transaction if you have set up the passed-in SessionFactory with a DataSource through the dataSource property of the LocalSessionFactoryBean class. Alternatively, you can specify explicitly the DataSource for which the transactions are supposed to be exposed through the dataSource property of the HibernateTransactionManager class.
HibernateTransactionManager 可以将 Hibernate JDBC Connection 导出为特定 DataSource 的普通 JDBC 访问代码。此功能允许在不使用 JTA 的情况下,通过混合 Hibernate 和 JDBC 数据访问进行高级事务划分,前提是您只访问一个数据库。 HibernateTransactionManager 会自动将 Hibernate 事务暴露为 JDBC 事务,如果您已通过 LocalSessionFactoryBean 类的 dataSource 属性设置了传入的 SessionFactoryDataSource 。或者,您可以通过 HibernateTransactionManager 类的 dataSource 属性显式指定要暴露事务的 DataSource

(#orm-hibernate-resources)5.3.6. Comparing Container-managed and Locally Defined Resources

5.3.6. 比较容器管理资源和本地定义资源

You can switch between a container-managed JNDI SessionFactory and a locally defined one without having to change a single line of application code. Whether to keep resource definitions in the container or locally within the application is mainly a matter of the transaction strategy that you use. Compared to a Spring-defined local SessionFactory, a manually registered JNDI SessionFactory does not provide any benefits. Deploying a SessionFactory through Hibernate’s JCA connector provides the added value of participating in the Java EE server’s management infrastructure, but does not add actual value beyond that.
您可以在容器管理的 JNDI SessionFactory 和本地定义的一个之间切换,而无需更改应用代码的一行。是否在容器内或本地应用内保留资源定义主要取决于您使用的交易策略。与 Spring 定义的本地 SessionFactory 相比,手动注册的 JNDI SessionFactory 没有任何优势。通过 Hibernate 的 JCA 连接器部署 SessionFactory ,可以增加参与 Java EE 服务器管理基础设施的价值,但并不增加实际价值之外的价值。

Spring’s transaction support is not bound to a container. When configured with any strategy other than JTA, transaction support also works in a stand-alone or test environment.
Spring 的事务支持不绑定到容器。当配置为除 JTA 以外的任何策略时,事务支持也可以在独立或测试环境中工作。
Especially in the typical case of single-database transactions, Spring’s single-resource local transaction support is a lightweight and powerful alternative to JTA.
特别在单数据库事务的典型情况下,Spring 的单资源本地事务支持是 JTA 的一个轻量级且强大的替代方案。
When you use local EJB stateless session beans to drive transactions, you depend both on an EJB container and on JTA, even if you access only a single database and use only stateless session beans to provide declarative transactions through container-managed transactions.
当您使用本地无状态会话 EJB 驱动事务时,即使您只访问单个数据库且仅使用无状态会话 EJB 通过容器管理的事务提供声明式事务,您也依赖于 EJB 容器和 JTA。
Direct use of JTA programmatically also requires a Java EE environment. JTA does not involve only container dependencies in terms of JTA itself and of JNDI DataSource instances. For non-Spring, JTA-driven Hibernate transactions, you have to use the Hibernate JCA connector or extra Hibernate transaction code with the TransactionManagerLookup configured for proper JVM-level caching.
直接以编程方式使用 JTA 还需要 Java EE 环境。JTA 不仅涉及 JTA 本身和 JNDI DataSource 实例的容器依赖。对于非 Spring,由 JTA 驱动的 Hibernate 事务,您必须使用 Hibernate JCA 连接器或带有 TransactionManagerLookup 配置的额外 Hibernate 事务代码,以实现适当的 JVM 级别缓存。

Spring-driven transactions can work as well with a locally defined Hibernate SessionFactory as they do with a local JDBC DataSource, provided they access a single database. Thus, you need only use Spring’s JTA transaction strategy when you have distributed transaction requirements. A JCA connector requires container-specific deployment steps, and ( obviously) JCA support in the first place.
Spring 驱动的事务可以与本地定义的 Hibernate SessionFactory 一样好地工作,就像它们与本地 JDBC DataSource 一样,前提是它们访问单个数据库。因此,只有在你有分布式事务需求时,才需要使用 Spring 的 JTA 事务策略。JCA 连接器需要特定的容器部署步骤,并且(显然)首先需要 JCA 支持。
This configuration requires more work than deploying a simple web application with local resource definitions and Spring-driven transactions. Also, you often need the Enterprise Edition of your container if you use, for example, WebLogic Express, which does not provide JCA.
此配置比部署使用本地资源定义和 Spring 驱动的简单 Web 应用程序需要更多工作。此外,如果您使用例如 WebLogic Express 这样的容器,它不提供 JCA,那么您通常需要使用容器的企业版。
A Spring application with local resources and transactions that span one single database works in any Java EE web container (without JTA, JCA, or EJB), such as Tomcat, Resin, or even plain Jetty.
一个具有本地资源和跨单个数据库事务的 Spring 应用程序可以在任何 Java EE Web 容器中运行(无需 JTA、JCA 或 EJB),例如 Tomcat、Resin,甚至是普通的 Jetty。
Additionally, you can easily reuse such a middle tier in desktop applications or test suites.
此外,您还可以轻松地在桌面应用程序或测试套件中重用这样的中间层。

All things considered, if you do not use EJBs, stick with local SessionFactory setup and Spring’s HibernateTransactionManager or JtaTransactionManager. You get all of the benefits, including proper transactional JVM-level caching and distributed transactions, without the inconvenience of container deployment. JNDI registration of a Hibernate SessionFactory through the JCA connector adds value only when used in conjunction with EJBs.
综合考虑,如果您不使用 EJBs,请坚持使用本地 SessionFactory 设置和 Spring 的 HibernateTransactionManagerJtaTransactionManager 。您将获得所有好处,包括适当的 JVM 级别事务缓存和分布式事务,而不必忍受容器部署的不便。通过 JCA 连接器将 Hibernate SessionFactory 进行 JNDI 注册,只有在与 EJBs 结合使用时才增加价值。

(#orm-hibernate-invalid-jdbc-access-error)5.3.7. Spurious Application Server Warnings with Hibernate

5.3.7. Hibernate 导致的虚假应用程序服务器警告

In some JTA environments with very strict XADataSource implementations (currently some WebLogic Server and WebSphere versions), when Hibernate is configured without regard to the JTA transaction manager for that environment, spurious warnings or exceptions can show up in the application server log.
在某些具有非常严格的 XADataSource 实现(目前一些 WebLogic Server 和 WebSphere 版本)的 JTA 环境中,当 Hibernate 未考虑该环境的 JTA 事务管理器进行配置时,应用程序服务器日志中可能会出现虚假的警告或异常。
These warnings or exceptions indicate that the connection being accessed is no longer valid or JDBC access is no longer valid, possibly because the transaction is no longer active. As an example, here is an actual exception from WebLogic:
这些警告或异常表明正在访问的连接已不再有效或 JDBC 访问已不再有效,可能是因为事务已不再活跃。以下是一个来自 WebLogic 的实际异常示例:

java.sql.SQLException: The transaction is no longer active - status: 'Committed'. No further JDBC access is allowed within this transaction.

Another common problem is a connection leak after JTA transactions, with Hibernate sessions (and potentially underlying JDBC connections) not getting closed properly.
另一个常见问题是 JTA 事务后的连接泄漏,Hibernate 会话(以及潜在的底层 JDBC 连接)未能正确关闭。

You can resolve such issues by making Hibernate aware of the JTA transaction manager, to which it synchronizes (along with Spring). You have two options for doing this:
您可以通过让 Hibernate 了解 JTA 事务管理器,从而与其同步(包括 Spring)来解决此类问题。您有两个选择来实现这一点:

  • Pass your Spring JtaTransactionManager bean to your Hibernate setup. The easiest way is a bean reference into the jtaTransactionManager property for your LocalSessionFactoryBean bean ( see Hibernate Transaction Setup). Spring then makes the corresponding JTA strategies available to Hibernate.
    将您的 Spring JtaTransactionManager Bean 传递到 Hibernate 配置中。最简单的方法是将您的 LocalSessionFactoryBean Bean 的 jtaTransactionManager 属性中的 Bean 引用(参见 Hibernate 事务设置)。然后 Spring 将相应的 JTA 策略提供给 Hibernate。

  • You may also configure Hibernate’s JTA-related properties explicitly, in particular " hibernate.transaction.coordinator_class", "hibernate.connection.handling_mode" and potentially " hibernate.transaction.jta.platform" in your "hibernateProperties" on LocalSessionFactoryBean (see Hibernate’s manual for details on those properties).
    您还可以显式配置 Hibernate 的 JTA 相关属性,特别是“hibernate.transaction.coordinator_class”、“hibernate.connection.handling_mode”以及可能还有“hibernate.transaction.jta.platform”,在您的“hibernateProperties”中(有关这些属性的详细信息,请参阅 Hibernate 手册)。

The remainder of this section describes the sequence of events that occur with and without Hibernate’s awareness of the JTA PlatformTransactionManager.
本节剩余部分描述了在有和没有 Hibernate 对 JTA PlatformTransactionManager 意识的情况下发生的事件序列。

When Hibernate is not configured with any awareness of the JTA transaction manager, the following events occur when a JTA transaction commits:
当 Hibernate 未配置对 JTA 事务管理器的任何感知时,当 JTA 事务提交时会发生以下事件:

  • The JTA transaction commits.
    JTA 事务提交。

  • Spring’s JtaTransactionManager is synchronized to the JTA transaction, so it is called back through an afterCompletion callback by the JTA transaction manager.
    Spring 的 JtaTransactionManager 与 JTA 事务同步,因此通过 JTA 事务管理器的 afterCompletion 回调进行调用。

  • Among other activities, this synchronization can trigger a callback by Spring to Hibernate, through Hibernate’s afterTransactionCompletion callback (used to clear the Hibernate cache), followed by an explicit close() call on the Hibernate session, which causes Hibernate to attempt to close() the JDBC Connection.
    在其它活动之中,这种同步可以触发 Spring 对 Hibernate 的回调,通过 Hibernate 的 afterTransactionCompletion 回调(用于清除 Hibernate 缓存),随后在 Hibernate 会话上显式调用 close() ,这导致 Hibernate 尝试 close() JDBC 连接。

  • In some environments, this Connection.close() call then triggers the warning or error, as the application server no longer considers the Connection to be usable, because the transaction has already been committed.
    在某些环境中,此 Connection.close() 调用随后触发警告或错误,因为应用服务器不再认为 Connection 可使用,因为事务已经提交。

When Hibernate is configured with awareness of the JTA transaction manager, the following events occur when a JTA transaction commits:
当 Hibernate 配置了 JTA 事务管理器的意识时,当 JTA 事务提交时,将发生以下事件:

  • The JTA transaction is ready to commit.
    JTA 事务准备提交。

  • Spring’s JtaTransactionManager is synchronized to the JTA transaction, so the transaction is called back through a beforeCompletion callback by the JTA transaction manager.
    Spring 的 JtaTransactionManager 与 JTA 事务同步,因此事务通过 JTA 事务管理器的 beforeCompletion 回调被调用回。

  • Spring is aware that Hibernate itself is synchronized to the JTA transaction and behaves differently than in the previous scenario. In particular, it aligns with Hibernate’s transactional resource management.
    Spring 知道 Hibernate 本身与 JTA 事务同步,并且与之前的情况表现不同。特别是,它与 Hibernate 的事务性资源管理保持一致。

  • The JTA transaction commits.
    JTA 事务提交。

  • Hibernate is synchronized to the JTA transaction, so the transaction is called back through an afterCompletion callback by the JTA transaction manager and can properly clear its cache.
    Hibernate 与 JTA 事务同步,因此事务通过 JTA 事务管理器的 afterCompletion 回调被调用,可以正确地清除其缓存。

(#orm-jpa)5.4. JPA

The Spring JPA, available under the org.springframework.orm.jpa package, offers comprehensive support for the Java Persistence API in a manner similar to the integration with Hibernate while being aware of the underlying implementation in order to provide additional features.
Spring JPA,位于 org.springframework.orm.jpa 包下,以类似于与 Hibernate 集成的风格,为 Java 持久化 API 提供全面支持,同时了解底层实现以便提供额外功能。

(#orm-jpa-setup)5.4.1. Three Options for JPA Setup in a Spring Environment

5.4.1. Spring 环境中 JPA 设置的三个选项

The Spring JPA support offers three ways of setting up the JPA EntityManagerFactory that is used by the application to obtain an entity manager.
Spring JPA 支持三种设置 JPA EntityManagerFactory 的方式,该方式由应用程序用于获取实体管理器。

(#orm-jpa-setup-lemfb)UsingLocalEntityManagerFactoryBean 使用LocalEntityManagerFactoryBean

You can use this option only in simple deployment environments such as stand-alone applications and integration tests.
您只能在简单的部署环境中使用此选项,例如独立应用程序和集成测试。

The LocalEntityManagerFactoryBean creates an EntityManagerFactory suitable for simple deployment environments where the application uses only JPA for data access. The factory bean uses the JPA PersistenceProvider auto-detection mechanism (according to JPA’s Java SE bootstrapping) and, in most cases, requires you to specify only the persistence unit name. The following XML example configures such a bean:
LocalEntityManagerFactoryBean 创建了一个适用于仅使用 JPA 进行数据访问的简单部署环境的 EntityManagerFactory 。工厂 Bean 使用 JPA PersistenceProvider 自动检测机制(根据 JPA 的 Java SE 启动),在大多数情况下,您只需指定持久化单元名称。以下 XML 示例配置了这样的 Bean:

<beans> <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="myPersistenceUnit"/> </bean> </beans>

This form of JPA deployment is the simplest and the most limited. You cannot refer to an existing JDBC DataSource bean definition, and no support for global transactions exists. Furthermore, weaving (byte-code transformation) of persistent classes is provider-specific, often requiring a specific JVM agent to be specified on startup.
这种 JPA 部署形式是最简单也是最有限的。您不能引用现有的 JDBC DataSource bean 定义,并且不存在对全局事务的支持。此外,持久化类的织入(字节码转换)是提供者特定的,通常需要在启动时指定特定的 JVM 代理。
This option is sufficient only for stand-alone applications and test environments, for which the JPA specification is designed.
此选项仅适用于独立应用程序和测试环境,JPA 规范正是为此类环境设计的。

(#orm-jpa-setup-jndi)Obtaining an EntityManagerFactory from JNDI

从 JNDI 获取 EntityManagerFactory

You can use this option when deploying to a Java EE server. Check your server’s documentation on how to deploy a custom JPA provider into your server, allowing for a different provider than the server’s default.
您可以在部署到 Java EE 服务器时使用此选项。请查阅您的服务器文档,了解如何将自定义 JPA 提供程序部署到您的服务器中,以便使用与服务器默认提供程序不同的提供程序。

Obtaining an EntityManagerFactory from JNDI (for example in a Java EE environment), is a matter of changing the XML configuration, as the following example shows:
获取 JNDI 中的 EntityManagerFactory (例如在 Java EE 环境中),只需更改 XML 配置即可,以下示例显示:

<beans> <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> </beans>

This action assumes standard Java EE bootstrapping. The Java EE server auto-detects persistence units (in effect, META-INF/persistence.xml files in application jars) and persistence-unit-ref entries in the Java EE deployment descriptor (for example, web.xml) and defines environment naming context locations for those persistence units.
此操作假定标准 Java EE 引导。Java EE 服务器自动检测持久化单元(实际上,是应用程序 jar 中的 META-INF/persistence.xml 文件)和 Java EE 部署描述符中的 persistence-unit-ref 条目(例如, web.xml ),并为这些持久化单元定义环境命名上下文位置。

In such a scenario, the entire persistence unit deployment, including the weaving (byte-code transformation) of persistent classes, is up to the Java EE server. The JDBC DataSource is defined through a JNDI location in the META-INF/persistence.xml file. EntityManager transactions are integrated with the server’s JTA subsystem. Spring merely uses the obtained EntityManagerFactory, passing it on to application objects through dependency injection and managing transactions for the persistence unit (typically through JtaTransactionManager).
在这种情况下,整个持久化单元部署,包括持久化类的织入(字节码转换),都由 Java EE 服务器负责。JDBC DataSource 通过 META-INF/persistence.xml 文件中的 JNDI 位置定义。 EntityManager 事务与服务器的 JTA 子系统集成。Spring 仅使用获得的 EntityManagerFactory ,通过依赖注入将其传递给应用程序对象,并管理持久化单元的事务(通常通过 JtaTransactionManager )。

If you use multiple persistence units in the same application, the bean names of such JNDI-retrieved persistence units should match the persistence unit names that the application uses to refer to them (for example, in @PersistenceUnit and @PersistenceContext annotations).
如果您在同一个应用程序中使用多个持久化单元,则此类通过 JNDI 检索的持久化单元的 bean 名称应与应用程序用于引用它们的持久化单元名称匹配(例如,在 @PersistenceUnit@PersistenceContext 注解中)。

(#orm-jpa-setup-lcemfb)UsingLocalContainerEntityManagerFactoryBean 使用

LocalContainerEntityManagerFactoryBean

You can use this option for full JPA capabilities in a Spring-based application environment. This includes web containers such as Tomcat, stand-alone applications, and integration tests with sophisticated persistence requirements.
您可以使用此选项在基于 Spring 的应用程序环境中实现完整的 JPA 功能。这包括 Tomcat 等 Web 容器、独立应用程序以及具有复杂持久性要求的集成测试。

If you want to specifically configure a Hibernate setup, an immediate alternative is to set up a native Hibernate LocalSessionFactoryBean instead of a plain JPA LocalContainerEntityManagerFactoryBean, letting it interact with JPA access code as well as native Hibernate access code. See Native Hibernate setup for JPA interaction for details.
如果您想专门配置 Hibernate 设置,一个直接的替代方案是设置原生 Hibernate LocalSessionFactoryBean ,而不是普通的 JPA LocalContainerEntityManagerFactoryBean ,让它既能与 JPA 访问代码交互,也能与原生 Hibernate 访问代码交互。有关 JPA 交互的原生 Hibernate 设置的详细信息,请参阅。

The LocalContainerEntityManagerFactoryBean gives full control over EntityManagerFactory configuration and is appropriate for environments where fine-grained customization is required. The LocalContainerEntityManagerFactoryBean creates a PersistenceUnitInfo instance based on the persistence.xml file, the supplied dataSourceLookup strategy, and the specified loadTimeWeaver. It is, thus, possible to work with custom data sources outside of JNDI and to control the weaving process. The following example shows a typical bean definition for a LocalContainerEntityManagerFactoryBean:
LocalContainerEntityManagerFactoryBean 提供了对 EntityManagerFactory 配置的完全控制,适用于需要精细定制的环境。 LocalContainerEntityManagerFactoryBean 根据提供的 persistence.xml 文件、 dataSourceLookup 策略和指定的 loadTimeWeaver 创建一个 PersistenceUnitInfo 实例。因此,可以在 JNDI 之外与自定义数据源一起工作,并控制织入过程。以下示例显示了 LocalContainerEntityManagerFactoryBean 的典型 Bean 定义:

<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>

The following example shows a typical persistence.xml file:
以下示例显示了一个典型的 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>

The <exclude-unlisted-classes/> shortcut indicates that no scanning for annotated entity classes is supposed to occur. An explicit 'true' value (<exclude-unlisted-classes>true</exclude-unlisted-classes/>) also means no scan. <exclude-unlisted-classes>false</exclude-unlisted-classes/> does trigger a scan. However, we recommend omitting the exclude-unlisted-classes element if you want entity class scanning to occur.
<exclude-unlisted-classes/> 快捷键表示不应进行标注实体类的扫描。显式的 'true' 值( <exclude-unlisted-classes>true</exclude-unlisted-classes/> )也表示不扫描。 <exclude-unlisted-classes>false</exclude-unlisted-classes/> 会触发扫描。然而,如果您希望进行实体类扫描,我们建议省略 exclude-unlisted-classes 元素。

Using the LocalContainerEntityManagerFactoryBean is the most powerful JPA setup option, allowing for flexible local configuration within the application. It supports links to an existing JDBC DataSource, supports both local and global transactions, and so on. However, it also imposes requirements on the runtime environment, such as the availability of a weaving-capable class loader if the persistence provider demands byte-code transformation.
使用 LocalContainerEntityManagerFactoryBean 是最强大的 JPA 配置选项,允许在应用程序中进行灵活的本地配置。它支持链接到现有的 JDBC DataSource ,支持本地和全局事务等。然而,它也对运行时环境提出了要求,例如,如果持久化提供者需要字节码转换,则必须提供具有织入功能的类加载器。

This option may conflict with the built-in JPA capabilities of a Java EE server. In a full Java EE environment, consider obtaining your EntityManagerFactory from JNDI. Alternatively, specify a custom persistenceXmlLocation on your LocalContainerEntityManagerFactoryBean definition (for example, META-INF/my-persistence.xml) and include only a descriptor with that name in your application jar files. Because the Java EE server looks only for default META-INF/persistence.xml files, it ignores such custom persistence units and, hence, avoids conflicts with a Spring-driven JPA setup upfront. (This applies to Resin 3.1, for example.)
此选项可能与 Java EE 服务器的内置 JPA 功能冲突。在完整的 Java EE 环境中,请考虑从 JNDI 获取您的 EntityManagerFactory 。或者,在您的 LocalContainerEntityManagerFactoryBean 定义(例如,META-INF/my-persistence.xml)中指定自定义的 persistenceXmlLocation ,并在您的应用程序 jar 文件中仅包含具有该名称的描述符。因为 Java EE 服务器只查找默认的 META-INF/persistence.xml 文件,它将忽略此类自定义持久化单元,从而避免与由 Spring 驱动的 JPA 设置的冲突。(例如,这适用于 Resin 3.1。)

The LoadTimeWeaver interface is a Spring-provided class that lets JPA ClassTransformer instances be plugged in a specific manner, depending on whether the environment is a web container or application server. Hooking ClassTransformers through an agent is typically not efficient. The agents work against the entire virtual machine and inspect every class that is loaded, which is usually undesirable in a production server environment.
LoadTimeWeaver 接口是一个 Spring 提供的类,允许 JPA ClassTransformer 实例以特定方式插入,具体取决于环境是否为 Web 容器或应用服务器。通过代理挂钩 ClassTransformers 通常效率不高。代理会对整个虚拟机进行操作,并检查加载的每个类,这在生产服务器环境中通常是不希望的。

Spring provides a number of LoadTimeWeaver implementations for various environments, letting ClassTransformer instances be applied only for each class loader and not for each VM.
Spring 为各种环境提供了多种 LoadTimeWeaver 实现,使得 ClassTransformer 实例仅应用于每个类加载器,而不是每个虚拟机。

See the Spring configuration in the AOP chapter for more insight regarding the LoadTimeWeaver implementations and their setup, either generic or customized to various platforms (such as Tomcat, JBoss and WebSphere).
查看 AOP 章节中的 Spring 配置,以了解更多关于 LoadTimeWeaver 实现及其设置的信息,无论是通用的还是针对各种平台(如 Tomcat、JBoss 和 WebSphere)定制的。

As described in Spring configuration, you can configure a context-wide LoadTimeWeaver by using the @EnableLoadTimeWeaving annotation or the context:load-time-weaver XML element. Such a global weaver is automatically picked up by all JPA LocalContainerEntityManagerFactoryBean instances. The following example shows the preferred way of setting up a load-time weaver, delivering auto-detection of the platform (e.g. Tomcat’s weaving-capable class loader or Spring’s JVM agent) and automatic propagation of the weaver to all weaver-aware beans:
如 Spring 配置中所述,您可以通过使用 @EnableLoadTimeWeaving 注解或 context:load-time-weaver XML 元素来配置一个上下文范围的 LoadTimeWeaver 。这样的全局织入器会自动被所有 JPA LocalContainerEntityManagerFactoryBean 实例获取。以下示例显示了设置负载时织入器的首选方法,它提供平台(例如 Tomcat 的具有织入功能的类加载器或 Spring 的 JVM 代理)的自检,并将织入器自动传播到所有织入器感知的 bean:

<context:load-time-weaver/> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> ... </bean>

However, you can, if needed, manually specify a dedicated weaver through the loadTimeWeaver property, as the following example shows:
然而,如果需要,您可以通过 loadTimeWeaver 属性手动指定一个专用织工,如下例所示:

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> </property> </bean>

No matter how the LTW is configured, by using this technique, JPA applications relying on instrumentation can run in the target platform (for example, Tomcat) without needing an agent.
无论 LTW 如何配置,通过使用这种技术,依赖工具的 JPA 应用程序可以在目标平台(例如,Tomcat)上运行,无需代理。
This is especially important when the hosting applications rely on different JPA implementations, because the JPA transformers are applied only at the class-loader level and are, thus, isolated from each other.
这尤其重要,因为托管应用程序依赖于不同的 JPA 实现时,因为 JPA 转换器仅在类加载器级别应用,因此彼此隔离。

(#orm-jpa-setup-multiple)Dealing with Multiple Persistence Units

处理多个持久化单元

For applications that rely on multiple persistence units locations (stored in various JARS in the classpath, for example), Spring offers the PersistenceUnitManager to act as a central repository and to avoid the persistence units discovery process, which can be expensive. The default implementation lets multiple locations be specified. These locations are parsed and later retrieved through the persistence unit name.
对于依赖于多个持久化单元位置(例如存储在类路径中的各种 JAR 文件中)的应用程序,Spring 提供了 PersistenceUnitManager 作为中央存储库,以避免昂贵的持久化单元发现过程。默认实现允许指定多个位置。这些位置将被解析,并通过持久化单元名称检索。
(By default, the classpath is searched for META-INF/persistence.xml files.) The following example configures multiple locations:
(默认情况下,类路径会搜索 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>

The default implementation allows customization of the PersistenceUnitInfo instances (before they are fed to the JPA provider) either declaratively (through its properties, which affect all hosted units) or programmatically (through the PersistenceUnitPostProcessor, which allows persistence unit selection). If no PersistenceUnitManager is specified, one is created and used internally by LocalContainerEntityManagerFactoryBean.
默认实现允许自定义 PersistenceUnitInfo 实例(在它们被提供给 JPA 提供者之前),无论是声明式(通过其属性,这些属性影响所有托管单元)还是程序式(通过 PersistenceUnitPostProcessor ,允许持久化单元选择)。如果没有指定 PersistenceUnitManager ,则会创建一个并由 LocalContainerEntityManagerFactoryBean 内部使用。

(#orm-jpa-setup-background)Background Bootstrapping

背景自举

LocalContainerEntityManagerFactoryBean supports background bootstrapping through the bootstrapExecutor property, as the following example shows:
LocalContainerEntityManagerFactoryBean 支持通过 bootstrapExecutor 属性进行后台引导,如下例所示:

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="bootstrapExecutor"> <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/> </property> </bean>

The actual JPA provider bootstrapping is handed off to the specified executor and then, running in parallel, to the application bootstrap thread. The exposed EntityManagerFactory proxy can be injected into other application components and is even able to respond to EntityManagerFactoryInfo configuration inspection. However, once the actual JPA provider is being accessed by other components (for example, calling createEntityManager), those calls block until the background bootstrapping has completed. In particular, when you use Spring Data JPA, make sure to set up deferred bootstrapping for its repositories as well.
实际的 JPA 提供程序引导工作交给指定的执行器,然后并行运行到应用程序引导线程。暴露的 EntityManagerFactory 代理可以注入到其他应用程序组件中,甚至能够响应 EntityManagerFactoryInfo 配置检查。然而,一旦实际的 JPA 提供程序被其他组件访问(例如,调用 createEntityManager ),这些调用将阻塞,直到后台引导完成。特别是当你使用 Spring Data JPA 时,确保为其仓库设置延迟引导。

(#orm-jpa-dao)5.4.2. Implementing DAOs Based on JPA:EntityManagerFactory andEntityManager

5.4.2. 基于 JPA 实现 DAOs: EntityManagerFactoryEntityManager

Although EntityManagerFactory instances are thread-safe, EntityManager instances are not. The injected JPA EntityManager behaves like an EntityManager fetched from an application server’s JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional EntityManager, if any. Otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe.
尽管 EntityManagerFactory 实例是线程安全的, EntityManager 实例则不是。注入的 JPA EntityManager 的行为类似于由 JPA 规范定义的从应用服务器的 JNDI 环境中获取的 EntityManager 。如果存在当前事务的 EntityManager ,它将所有调用委托给它。否则,它将回退到每个操作创建的新 EntityManager ,从而使其使用线程安全。

It is possible to write code against the plain JPA without any Spring dependencies, by using an injected EntityManagerFactory or EntityManager. Spring can understand the @PersistenceUnit and @PersistenceContext annotations both at the field and the method level if a PersistenceAnnotationBeanPostProcessor is enabled. The following example shows a plain JPA DAO implementation that uses the @PersistenceUnit annotation:
可以编写不依赖 Spring 的纯 JPA 代码,通过使用注入的 EntityManagerFactoryEntityManager 。如果启用了 PersistenceAnnotationBeanPostProcessor ,Spring 可以在字段和方法级别理解 @PersistenceUnit@PersistenceContext 注解。以下示例展示了使用 @PersistenceUnit 注解的纯 JPA DAO 实现:

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; } }

The preceding DAO has no dependency on Spring and still fits nicely into a Spring application context. Moreover, the DAO takes advantage of annotations to require the injection of the default EntityManagerFactory, as the following example bean definition shows:
前一个 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>

As an alternative to explicitly defining a PersistenceAnnotationBeanPostProcessor, consider using the Spring context:annotation-config XML element in your application context configuration. Doing so automatically registers all Spring standard post-processors for annotation-based configuration, including CommonAnnotationBeanPostProcessor and so on.
作为显式定义 PersistenceAnnotationBeanPostProcessor 的替代方案,考虑在应用程序上下文配置中使用 Spring context:annotation-config XML 元素。这样做将自动注册所有基于注解的配置的 Spring 标准后处理器,包括 CommonAnnotationBeanPostProcessor 等等。

Consider the following example:
考虑以下示例:

<beans> <!-- post-processors for all standard config annotations --> <context:annotation-config/> <bean id="myProductDao" class="product.ProductDaoImpl"/> </beans>

The main problem with such a DAO is that it always creates a new EntityManager through the factory. You can avoid this by requesting a transactional EntityManager (also called a “shared EntityManager” because it is a shared, thread-safe proxy for the actual transactional EntityManager) to be injected instead of the factory. The following example shows how to do so:
该类型 DAO 的主要问题是它总是通过工厂创建一个新的 EntityManager 。您可以通过请求注入一个事务性的 EntityManager (也称为“共享 EntityManager”,因为它是一个共享的、线程安全的代理,用于实际的交易性 EntityManager)来避免这种情况。以下示例展示了如何做到这一点:

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 } }

The @PersistenceContext annotation has an optional attribute called type, which defaults to PersistenceContextType.TRANSACTION. You can use this default to receive a shared EntityManager proxy. The alternative, PersistenceContextType.EXTENDED, is a completely different affair. This results in a so-called extended EntityManager, which is not thread-safe and, hence, must not be used in a concurrently accessed component, such as a Spring-managed singleton bean. Extended EntityManager instances are only supposed to be used in stateful components that, for example, reside in a session, with the lifecycle of the EntityManager not tied to a current transaction but rather being completely up to the application.
@PersistenceContext 注解有一个可选属性称为 type ,默认值为 PersistenceContextType.TRANSACTION 。您可以使用此默认值来接收一个共享的 EntityManager 代理。另一种选择, PersistenceContextType.EXTENDED ,是完全不同的事情。这导致了一个所谓的扩展 EntityManager ,它不是线程安全的,因此不能用于并发访问的组件,例如 Spring 管理的单例 bean。扩展 EntityManager 实例仅应在具有状态的组件中使用,例如位于会话中的组件,其生命周期与 EntityManager 的当前事务无关,而是完全由应用程序决定。

The injected EntityManager is Spring-managed (aware of the ongoing transaction). Even though the new DAO implementation uses method-level injection of an EntityManager instead of an EntityManagerFactory, no change is required in the application context XML, due to annotation usage.
注入的 EntityManager 是 Spring 管理的(了解当前的事务)。尽管新的 DAO 实现使用方法级别的 EntityManager 注入代替了 EntityManagerFactory ,但由于使用了注解,无需在应用程序上下文 XML 中进行任何更改。

The main advantage of this DAO style is that it depends only on the Java Persistence API. No import of any Spring class is required. Moreover, as the JPA annotations are understood, the injections are applied automatically by the Spring container.
这种 DAO 风格的主要优势是它仅依赖于 Java 持久化 API。无需导入任何 Spring 类。此外,由于理解了 JPA 注解,注入将由 Spring 容器自动应用。
This is appealing from a non-invasiveness perspective and can feel more natural to JPA developers.
这是从非侵入性角度来看很有吸引力,并且对于 JPA 开发者来说可能感觉更自然。

(#orm-jpa-tx)5.4.3. Spring-driven JPA transactions

5.4.3. 由 Spring 驱动的 JPA 事务

We strongly encourage you to read Declarative Transaction Management, if you have not already done so, to get more detailed coverage of Spring’s declarative transaction support.
我们强烈建议您阅读《声明式事务管理》,如果您还没有阅读过,以获取对 Spring 声明式事务支持的更详细覆盖。

The recommended strategy for JPA is local transactions through JPA’s native transaction support. Spring’s JpaTransactionManager provides many capabilities known from local JDBC transactions (such as transaction-specific isolation levels and resource-level read-only optimizations) against any regular JDBC connection pool (no XA requirement).
JPA 的推荐策略是通过 JPA 的本地事务支持进行本地事务。Spring 的 JpaTransactionManager 为任何常规 JDBC 连接池提供了许多来自本地 JDBC 事务的能力(例如特定事务的隔离级别和资源级别的只读优化)(无需 XA 要求)。

Spring JPA also lets a configured JpaTransactionManager expose a JPA transaction to JDBC access code that accesses the same DataSource, provided that the registered JpaDialect supports retrieval of the underlying JDBC Connection. Spring provides dialects for the EclipseLink and Hibernate JPA implementations. See the next section for details on the JpaDialect mechanism.
Spring JPA 允许配置的 JpaTransactionManager 向访问相同 DataSource 的 JDBC 访问代码暴露 JPA 事务,前提是注册的 JpaDialect 支持检索底层的 JDBC Connection 。Spring 为 EclipseLink 和 Hibernate JPA 实现提供了方言。有关 JpaDialect 机制的详细信息,请参阅下一节。

As an immediate alternative, Spring’s native HibernateTransactionManager is capable of interacting with JPA access code, adapting to several Hibernate specifics and providing JDBC interaction. This makes particular sense in combination with LocalSessionFactoryBean setup. See Native Hibernate Setup for JPA Interaction for details.
作为一个即时替代方案,Spring 的本地 HibernateTransactionManager 能够与 JPA 访问代码交互,适应多个 Hibernate 特定功能,并提供 JDBC 交互。这与 LocalSessionFactoryBean 设置结合使用尤其有意义。有关详细信息,请参阅“原生 Hibernate 设置以实现 JPA 交互”。

(#orm-jpa-dialect)5.4.4. UnderstandingJpaDialect andJpaVendorAdapter

5.4.4. 理解 JpaDialectJpaVendorAdapter

As an advanced feature, JpaTransactionManager and subclasses of AbstractEntityManagerFactoryBean allow a custom JpaDialect to be passed into the jpaDialect bean property. A JpaDialect implementation can enable the following advanced features supported by Spring, usually in a vendor-specific manner:
作为一个高级功能, JpaTransactionManager 及其子类允许将自定义的 JpaDialect 传递给 jpaDialect 的 bean 属性。一个 JpaDialect 实现可以启用 Spring 支持的以下高级功能,通常以厂商特定的方式:

  • Applying specific transaction semantics (such as custom isolation level or transaction timeout)
    应用特定的交易语义(例如自定义隔离级别或事务超时)

  • Retrieving the transactional JDBC Connection (for exposure to JDBC-based DAOs)
    检索事务性 JDBC Connection (用于对基于 JDBC 的 DAO 的暴露)

  • Advanced translation of PersistenceException to Spring’s DataAccessException
    高级翻译 PersistenceException 到 Spring 的 DataAccessException

This is particularly valuable for special transaction semantics and for advanced translation of exception. The default implementation (DefaultJpaDialect) does not provide any special abilities and, if the features listed earlier are required, you have to specify the appropriate dialect.
这对于特殊事务语义和异常的高级翻译特别有价值。默认实现( DefaultJpaDialect )不提供任何特殊功能,如果需要前面列出的功能,您必须指定适当的方言。

As an even broader provider adaptation facility primarily for Spring’s full-featured LocalContainerEntityManagerFactoryBean setup, JpaVendorAdapter combines the capabilities of JpaDialect with other provider-specific defaults. Specifying a HibernateJpaVendorAdapter or EclipseLinkJpaVendorAdapter is the most convenient way of auto-configuring an EntityManagerFactory setup for Hibernate or EclipseLink, respectively. Note that those provider adapters are primarily designed for use with Spring-driven transaction management (that is, for use with JpaTransactionManager).
作为一个更广泛的提供者适配设施,主要用于 Spring 的全面功能 LocalContainerEntityManagerFactoryBean 设置, JpaVendorAdapter 结合了 JpaDialect 的功能以及其他特定提供者的默认设置。指定 HibernateJpaVendorAdapterEclipseLinkJpaVendorAdapter 是自动配置 Hibernate 或 EclipseLink 的 EntityManagerFactory 设置的最便捷方式。请注意,这些提供者适配器主要是为与 Spring 驱动的交易管理(即与 JpaTransactionManager 一起使用)而设计的。

See the JpaDialect and JpaVendorAdapter javadoc for more details of its operations and how they are used within Spring’s JPA support.
查看 JpaDialectJpaVendorAdapter 的 javadoc 以获取其操作的更多详细信息以及它们如何在 Spring 的 JPA 支持中使用。

(#orm-jpa-jta)5.4.5. Setting up JPA with JTA Transaction Management

5.4.5. 配置 JPA 与 JTA 事务管理

As an alternative to JpaTransactionManager, Spring also allows for multi-resource transaction coordination through JTA, either in a Java EE environment or with a stand-alone transaction coordinator, such as Atomikos. Aside from choosing Spring’s JtaTransactionManager instead of JpaTransactionManager, you need to take few further steps:
作为 JpaTransactionManager 的替代方案,Spring 还允许通过 JTA 进行多资源事务协调,无论是在 Java EE 环境中还是在独立的交易协调器(如 Atomikos)中。除了选择 Spring 的 JtaTransactionManager 而不是 JpaTransactionManager 之外,您还需要采取一些额外的步骤:

  • The underlying JDBC connection pools need to be XA-capable and be integrated with your transaction coordinator. This is usually straightforward in a Java EE environment, exposing a different kind of DataSource through JNDI. See your application server documentation for details. Analogously, a standalone transaction coordinator usually comes with special XA-integrated DataSource variants. Again, check its documentation.
    底层 JDBC 连接池需要具备 XA 能力,并集成到您的事务协调器中。在 Java EE 环境中,这通常很简单,通过 JNDI 暴露不同类型的 DataSource 。请参阅您的应用服务器文档以获取详细信息。类似地,独立的交易协调器通常附带特殊的 XA 集成 DataSource 变体。再次检查其文档。

  • The JPA EntityManagerFactory setup needs to be configured for JTA. This is provider-specific, typically through special properties to be specified as jpaProperties on LocalContainerEntityManagerFactoryBean. In the case of Hibernate, these properties are even version-specific. See your Hibernate documentation for details.
    JPA EntityManagerFactory 设置需要配置为 JTA。这是供应商特定的,通常通过在 LocalContainerEntityManagerFactoryBean 上指定特殊的属性 jpaProperties 来完成。在 Hibernate 的情况下,这些属性甚至是版本特定的。请参阅 Hibernate 文档以获取详细信息。

  • Spring’s HibernateJpaVendorAdapter enforces certain Spring-oriented defaults, such as the connection release mode, on-close, which matches Hibernate’s own default in Hibernate 5.0 but not any more in Hibernate 5.1+. For a JTA setup, make sure to declare your persistence unit transaction type as "JTA". Alternatively, set Hibernate 5.2’s hibernate.connection.handling_mode property to DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT to restore Hibernate’s own default. See Spurious Application Server Warnings with Hibernate for related notes.
    春季的 HibernateJpaVendorAdapter 强制执行某些面向 Spring 的默认设置,例如连接释放模式 on-close ,这与 Hibernate 5.0 中的 Hibernate 自身默认设置相匹配,但在 Hibernate 5.1+中不再匹配。对于 JTA 配置,请确保将持久化单元的事务类型声明为"JTA" 。或者,将 Hibernate 5.2 的 hibernate.connection.handling_mode 属性设置为 DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT 以恢复 Hibernate 的自身默认设置。有关相关说明,请参阅与 Hibernate 相关的应用程序服务器警告。

  • Alternatively, consider obtaining the EntityManagerFactory from your application server itself (that is, through a JNDI lookup instead of a locally declared LocalContainerEntityManagerFactoryBean). A server-provided EntityManagerFactory might require special definitions in your server configuration (making the deployment less portable) but is set up for the server’s JTA environment.
    或者,考虑从您的应用服务器本身获取 EntityManagerFactory (即通过 JNDI 查找而不是本地声明的 LocalContainerEntityManagerFactoryBean )。服务器提供的 EntityManagerFactory 可能需要在您的服务器配置中进行特殊定义(使得部署不太便携),但已为服务器的 JTA 环境设置好。

(#orm-jpa-hibernate)5.4.6. Native Hibernate Setup and Native Hibernate Transactions for JPA Interaction

5.4.6. 本地 Hibernate 设置和 JPA 交互的本地 Hibernate 事务

A native LocalSessionFactoryBean setup in combination with HibernateTransactionManager allows for interaction with @PersistenceContext and other JPA access code. A Hibernate SessionFactory natively implements JPA’s EntityManagerFactory interface now and a Hibernate Session handle natively is a JPA EntityManager. Spring’s JPA support facilities automatically detect native Hibernate sessions.
原生 LocalSessionFactoryBean 配置与 HibernateTransactionManager 结合使用,允许与 @PersistenceContext 及其他 JPA 访问代码进行交互。Hibernate SessionFactory 现在原生实现了 JPA 的 EntityManagerFactory 接口,Hibernate Session 处理器原生就是一个 JPA EntityManager 。Spring 的 JPA 支持设施自动检测原生 Hibernate 会话。

Such native Hibernate setup can, therefore, serve as a replacement for a standard JPA LocalContainerEntityManagerFactoryBean and JpaTransactionManager combination in many scenarios, allowing for interaction with SessionFactory.getCurrentSession() (and also HibernateTemplate) next to @PersistenceContext EntityManager within the same local transaction. Such a setup also provides stronger Hibernate integration and more configuration flexibility, because it is not constrained by JPA bootstrap contracts.
此类原生 Hibernate 设置因此可以在许多场景下作为标准 JPA LocalContainerEntityManagerFactoryBeanJpaTransactionManager 组合的替代品,允许在同一个本地事务中与 SessionFactory.getCurrentSession() (以及 HibernateTemplate )相邻的 @PersistenceContext EntityManager 进行交互。这种设置还提供了更强的 Hibernate 集成和更多的配置灵活性,因为它不受 JPA 引导合约的限制。

You do not need HibernateJpaVendorAdapter configuration in such a scenario, since Spring’s native Hibernate setup provides even more features (for example, custom Hibernate Integrator setup, Hibernate 5.3 bean container integration, and stronger optimizations for read-only transactions).
在这种情况下,您不需要 HibernateJpaVendorAdapter 配置,因为 Spring 的本地 Hibernate 设置提供了更多功能(例如,自定义 Hibernate 集成器设置、Hibernate 5.3 Bean 容器集成以及针对只读事务的更强优化)。
Last but not least, you can also express native Hibernate setup through LocalSessionFactoryBuilder, seamlessly integrating with @Bean style configuration (no FactoryBean involved).
最后但同样重要的是,您也可以通过 LocalSessionFactoryBuilder 表达本地的 Hibernate 配置,无缝地与 @Bean 风格的配置集成(不涉及 FactoryBean )。

LocalSessionFactoryBean and LocalSessionFactoryBuilder support background bootstrapping, just as the JPA LocalContainerEntityManagerFactoryBean does. See Background Bootstrapping for an introduction.
LocalSessionFactoryBeanLocalSessionFactoryBuilder 支持后台引导,就像 JPA LocalContainerEntityManagerFactoryBean 一样。请参阅后台引导以获取介绍。

On LocalSessionFactoryBean, this is available through the bootstrapExecutor property. On the programmatic LocalSessionFactoryBuilder, an overloaded buildSessionFactory method takes a bootstrap executor argument.
LocalSessionFactoryBean 上,这可以通过 bootstrapExecutor 属性获得。在程序化 LocalSessionFactoryBuilder 中,一个重载的 buildSessionFactory 方法接受一个引导执行器参数。

ON THIS PAGE