Spring数据访问和数据访问层与业务或服务层之间的交互

时间:2022-11-17 14:15:03

版本 6.0.0

Spring数据访问和数据访问层与业务或服务层之间的交互

参考文档的这一部分涉及数据访问和 数据访问层与业务或服务层之间的交互。

Spring的全面事务管理支持已经详细介绍, 然后全面涵盖各种数据访问框架和技术 Spring 框架与之集成。

1. 交易管理

全面的事务支持是使用Spring的最令人信服的理由之一。 框架。Spring 框架为事务提供了一致的抽象 具有以下优势的管理:

  • 跨不同事务 API(如 Java)的一致编程模型 事务 API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA)。
  • 支持声明式事务管理。
  • 用于编程事务管理的更简单的 API 而不是复杂的事务 API,例如 JTA。
  • 与 Spring 的数据访问抽象完美集成。

以下部分描述了 Spring 框架的事务特性和 技术:

  • Spring 框架事务支持的优势 模型描述了为什么你会使用Spring Framework的事务抽象 而不是 EJB 容器管理事务 (CMT) 或选择在本地驱动 通过专有 API 进行交易,例如 Hibernate。
  • 了解 Spring 框架事务抽象概述了核心类,并描述了如何配置和获取来自各种来源的实例。DataSource
  • 将资源与事务同步说明 应用程序代码如何确保创建、重用和清理资源 适当地。
  • 声明性事务管理描述了对 声明式事务管理。
  • 程序化事务管理涵盖对以下各项的支持 编程(即显式编码)事务管理。
  • 事务绑定事件描述如何使用应用程序 事务中的事件。

本章还包括对最佳实践、应用服务器集成、 以及常见问题的解决方案。

1.1. Spring 框架事务支持模型的优势

传统上,EE 应用程序开发人员有两种事务管理选择: 全球或本地交易,两者都有深刻的局限性。全球 和本地事务管理将在接下来的两个部分中进行回顾,然后是 讨论 Spring 框架的事务管理支持如何解决 全局和本地事务模型的局限性。

1.1.1. 全球交易

全局事务允许您使用多个事务资源,通常 关系数据库和消息队列。应用程序服务器管理全局 通过 JTA 进行交易,这是一个繁琐的 API(部分原因是 异常模型)。此外,JTA通常需要来自 JNDI,这意味着您还需要使用 JNDI 才能使用 JTA。用途 的全局事务限制了应用程序代码的任何潜在重用,因为 JTA 是 通常仅在应用程序服务器环境中可用。​​UserTransaction​

以前,使用全局事务的首选方法是通过 EJB CMT (容器管理事务)。CMT 是声明式交易的一种形式 管理(有别于程序化事务管理)。EJB CMT 消除了与事务相关的 JNDI 查找的需要,尽管使用了 EJB 本身需要使用 JNDI。它消除了大部分但不是全部的写入需求 用于控制事务的 Java 代码。显着的缺点是CMT与JTA绑定。 和应用程序服务器环境。此外,它仅在选择时才可用 在 EJB 中实现业务逻辑(或至少在事务性 EJB 外观后面)。这 一般来说,EJB的负面因素是如此之大,以至于这不是一个有吸引力的主张, 特别是面对声明式事务管理的令人信服的替代方案。

1.1.2. 本地交易

本地事务是特定于资源的,例如与 JDBC 关联的事务 连接。本地事务可能更易于使用,但有一个明显的缺点: 它们不能跨多个事务资源工作。例如,管理 使用 JDBC 连接的事务不能在全局 JTA 事务中运行。因为 应用程序服务器不参与事务管理,它不能帮助确保 跨多个资源的正确性。(值得注意的是,大多数应用程序使用 单个事务资源。另一个缺点是本地交易是侵入性的 到编程模型。

1.1.3. Spring 框架的一致编程模型

Spring 解决了全球和本地交易的缺点。它让 应用程序开发人员在任何环境中都使用一致的编程模型。 您编写一次代码,它就可以从不同的事务管理中受益 不同环境中的策略。Spring 框架提供了声明式和 程序化事务管理。大多数用户更喜欢声明式事务 管理,我们在大多数情况下建议这样做。

通过编程事务管理,开发人员可以使用 Spring 框架 事务抽象,可以在任何底层事务基础结构上运行。 使用首选的声明性模型,开发人员通常编写很少或没有代码 与事务管理相关,因此不依赖于 Spring 框架 事务 API 或任何其他事务 API。

您是否需要应用程序服务器进行事务管理?

Spring 框架的事务管理支持改变了传统的规则: 当企业 Java 应用程序需要应用程序服务器时。

特别是,您不需要纯粹用于声明性事务的应用程序服务器 通过 EJB。事实上,即使您的应用服务器具有强大的 JTA 功能, 你可能会决定 Spring 框架的声明式事务提供更多的功能和 比 EJB CMT 更高效的编程模型。

通常,仅当应用程序需要时才需要应用程序服务器的 JTA 功能。 处理跨多个资源的事务,这不是许多资源的要求 应用。许多高端应用程序使用单个高度可扩展的数据库(例如 甲骨文 RAC) 取而代之。独立的事务管理器(如Atomikos Transactions和JOTM) 是其他选项。当然,您可能需要其他应用程序服务器功能,例如 Java Message Service (JMS) 和 Jakarta EE Connector Architecture (JCA)。

Spring 框架使您可以选择何时将应用程序扩展到完全 加载的应用程序服务器。使用 EJB 的唯一替代方法的日子已经一去不复返了 CMT或JTA是用本地事务(例如JDBC连接上的事务)编写代码 如果您需要该代码在容器管理的全局范围内运行,则需要大量返工 交易。使用 Spring 框架,只有 配置文件需要更改(而不是您的代码)。

1.2. 理解 Spring 框架事务抽象

Spring 事务抽象的关键是事务策略的概念。一个 事务策略由 A 定义,具体接口为命令式 事务管理和反应式接口 事务管理。以下清单显示了 API 的定义:​​TransactionManager​​​​org.springframework.transaction.PlatformTransactionManager​​​​org.springframework.transaction.ReactiveTransactionManager​​​​PlatformTransactionManager​

public interface PlatformTransactionManager extends TransactionManager {

TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

void commit(TransactionStatus status) throws TransactionException;

void rollback(TransactionStatus status) throws TransactionException;
}

这主要是一个服务提供程序接口 (SPI),尽管您可以从应用程序代码以编程方式使用它。因为是一个接口,所以它可以很容易地被嘲笑或存根为 必要。它不依赖于查找策略,例如JNDI.实现的定义与任何其他对象(或bean)相同。 在 Spring Framework IoC 容器中。仅此好处就使 Spring 框架 事务是一个有价值的抽象,即使您使用 JTA 也是如此。你可以测试 事务代码比直接使用 JTA 容易得多。​​PlatformTransactionManager​​​​PlatformTransactionManager​

再次,为了与春天的哲学保持一致,可以抛出 通过任何接口的方法都是未选中的(那 是,它扩展了类)。事务基础结构 失败几乎总是致命的。在极少数情况下,应用程序代码实际上可以 从事务失败中恢复,应用程序开发人员仍然可以选择捕获 和处理。突出的一点是开发人员不是*这样做的。​​TransactionException​​​​PlatformTransactionManager​​​​java.lang.RuntimeException​​​​TransactionException​

该方法返回一个对象,具体取决于参数。返回的可能表示 新事务或可以表示现有事务(如果是匹配事务) 存在于当前调用堆栈中。后一种情况的含义是,与 Jakarta EE 事务上下文,与 执行。​​getTransaction(..)​​​​TransactionStatus​​​​TransactionDefinition​​​​TransactionStatus​​​​TransactionStatus​

从Spring Framework 5.2开始,Spring还提供了事务管理抽象 使用反应式类型或 Kotlin 协程的反应式应用程序。以下 列表显示由以下人员定义的交易策略:​​org.springframework.transaction.ReactiveTransactionManager​

public interface ReactiveTransactionManager extends TransactionManager {

Mono<ReactiveTransaction> getReactiveTransaction(TransactionDefinition definition) throws TransactionException;

Mono<Void> commit(ReactiveTransaction status) throws TransactionException;

Mono<Void> rollback(ReactiveTransaction status) throws TransactionException;
}

反应式事务管理器主要是一个服务提供者接口 (SPI), 尽管您可以从您的 应用程序代码。因为是一个界面,所以很容易 必要时嘲笑或存根。​​ReactiveTransactionManager​

该接口指定:​​TransactionDefinition​

  • 传播:通常,事务范围内的所有代码都在 那笔交易。但是,您可以指定行为,如果 当事务上下文已存在时,将运行事务方法。为 例如,代码可以继续在现有事务中运行(常见情况),或者 可以暂停现有事务并创建新事务。春天 提供了 EJB CMT 中熟悉的所有事务传播选项。要阅读 关于 Spring 中事务传播的语义,请参阅事务传播。
  • 隔离:此事务与其他事务的工作隔离的程度 交易。例如,此事务是否可以看到来自其他事务的未提交写入 交易?
  • 超时:此事务在超时并自动回滚之前运行的时间 通过底层事务基础结构。
  • 只读状态:当代码读取但 不修改数据。在某些方面,只读事务可能是一个有用的优化 情况,例如当您使用休眠时。

这些设置反映了标准的事务概念。如有必要,请参阅资源 讨论事务隔离级别和其他核心事务概念。 理解这些概念对于使用 Spring 框架或任何 事务管理解决方案。

该接口为事务代码提供了一种简单的方法 控制事务执行和查询事务状态。这些概念应该是 熟悉,因为它们对所有事务 API 都是通用的。以下清单显示了界面:​​TransactionStatus​​​​TransactionStatus​

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {

@Override
boolean isNewTransaction();

boolean hasSavepoint();

@Override
void setRollbackOnly();

@Override
boolean isRollbackOnly();

void flush();

@Override
boolean isCompleted();
}

无论您在 春天,定义正确的实现是绝对必要的。 通常通过依赖关系注入来定义此实现。​​TransactionManager​

​TransactionManager​​实现通常需要了解以下环境: 他们工作:JDBC,JTA,Hibernate等。以下示例演示如何 定义一个本地实现(在本例中,使用 plain JDBC.)​​PlatformTransactionManager​

您可以通过创建类似于以下内容的 Bean 来定义 JDBC:​​DataSource​

<bean  class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>

然后,相关 bean 定义具有对定义的引用。它应类似于以下示例:​​PlatformTransactionManager​​​​DataSource​

<bean  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

如果您在 Jakarta EE 容器中使用 JTA,则使用容器,获得 通过JNDI,与Spring's一起。以下示例 显示了 JTA 和 JNDI 查找版本的外观:​​DataSource​​​​JtaTransactionManager​

<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
https://www.springframework.org/schema/jee/spring-jee.xsd">

<jee:jndi-lookup jndi-name="jdbc/jpetstore"/>

<bean class="org.springframework.transaction.jta.JtaTransactionManager" />

<!-- other <bean/> definitions here -->

</beans>

不需要知道(或任何其他 特定资源),因为它使用容器的全局事务管理 基础设施。​​JtaTransactionManager​​​​DataSource​

在所有 Spring 事务设置中,应用程序代码不需要更改。您可以更改 如何仅通过更改配置来管理事务,即使该更改意味着 从本地事务转移到全局事务,反之亦然。

1.2.1. 休眠事务设置

您还可以轻松使用 Hibernate 本地事务,如以下示例所示。 在这种情况下,您需要定义一个休眠,您的 应用程序代码可用于获取休眠实例。​​LocalSessionFactoryBean​​​​Session​

Thebean 定义类似于前面显示的本地 JDBC 示例 因此,以下示例中未显示。​​DataSource​

在这种情况下,Thebean属于该类型。在 与需要引用的方式相同,需要引用。以下 示例声明和豆子:​​txManager​​​​HibernateTransactionManager​​​​DataSourceTransactionManager​​​​DataSource​​​​HibernateTransactionManager​​​​SessionFactory​​​​sessionFactory​​​​txManager​

<bean  class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>

<bean class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

如果使用 Hibernate 和 Jakarta EE 容器管理的 JTA 事务,则应使用 与前面的 JDBC JTA 示例中相同,如下所示 示例显示。此外,建议通过其使Hibernate知道JTA 事务协调器,可能还有其连接释放模式配置:​​JtaTransactionManager​

<bean  class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.transaction.coordinator_class=jta
hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>
</property>
</bean>

<bean class="org.springframework.transaction.jta.JtaTransactionManager"/>

或者,您也可以将 ther传递给您的以强制执行相同的默认值:​​JtaTransactionManager​​​​LocalSessionFactoryBean​

<bean  class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
<property name="jtaTransactionManager" ref="txManager"/>
</bean>

<bean class="org.springframework.transaction.jta.JtaTransactionManager"/>

1.3. 将资源与事务同步

如何创建不同的事务管理器以及如何将它们链接到相关资源 需要同步到事务(例如,到 JDBC,到休眠, 等等)现在应该很清楚了。本节介绍应用程序如何编码 (直接或间接地,通过使用持久性 API,如 JDBC、Hibernate 或 JPA) 确保正确创建、重用和清理这些资源。该部分 还讨论了如何(可选)通过 相关。​​DataSourceTransactionManager​​​​DataSource​​​​HibernateTransactionManager​​​​SessionFactory​​​​TransactionManager​

1.3.1. 高级同步方法

首选方法是使用 Spring *别的基于模板的持久性 集成 API 或将本机 ORM API 与事务感知工厂 Bean 一起使用,或 用于管理本机资源工厂的代理。这些事务感知解决方案 内部处理资源创建和重用、清理、可选事务 资源同步和异常映射。因此,用户数据访问代码确实 不必处理这些任务,但可以完全专注于非样板 持久性逻辑。通常,您使用本机ORM API或采用模板方法 对于 JDBC 访问,请使用。这些解决方案将在后续中详细介绍 部分。​​JdbcTemplate​

1.3.2. 低级同步方法

诸如(对于JDBC),(对于JPA),(对于Hibernate)等类存在于较低的级别。当您想要 直接处理本机持久性 API 的资源类型的应用程序代码, 您可以使用这些类来确保获得正确的 Spring 框架管理的实例, 事务(可选)同步,流程中发生的异常是 正确映射到一致的 API。​​DataSourceUtils​​​​EntityManagerFactoryUtils​​​​SessionFactoryUtils​

例如,在 JDBC 的情况下,而不是传统的 JDBC 调用方法 方法上,你可以改用 Spring 的类,如下所示:​​getConnection()​​​​DataSource​​​​org.springframework.jdbc.datasource.DataSourceUtils​

Connection conn = DataSourceUtils.getConnection(dataSource);

如果现有事务已具有同步(链接)的连接,则 返回实例。否则,方法调用将触发创建新的 连接,(可选)同步到任何现有事务并已建立 可用于同一事务中的后续重用。如前所述,anyis 包装在一个 Spring 框架中,一个 的 Spring 框架的未选中类型层次结构。这种方法 为您提供比从和轻松获得的更多信息 确保跨数据库甚至跨不同持久性技术的可移植性。​​SQLException​​​​CannotGetJdbcConnectionException​​​​DataAccessException​​​​SQLException​

这种方法也可以在没有 Spring 事务管理的情况下工作(事务 同步是可选的),因此无论您是否将 Spring 用于 事务管理。

当然,一旦你使用了 Spring 的 JDBC 支持、JPA 支持或 Hibernate 支持, 您通常不希望使用其他帮助程序类, 因为通过 Spring 抽象工作比直接工作更快乐 使用相关 API。例如,如果使用 Springorpackage 来简化 JDBC 的使用,则会发生正确的连接检索 在幕后,您无需编写任何特殊代码。​​DataSourceUtils​​​​JdbcTemplate​​​​jdbc.object​

1.3.3. ​​TransactionAwareDataSourceProxy​

在最低的层次上存在类。这是一个 目标的代理,它包装目标以增加对 弹簧管理的交易。在这方面,它类似于雅加达EE服务器提供的事务性JNDI。​​TransactionAwareDataSourceProxy​​​​DataSource​​​​DataSource​​​​DataSource​

你几乎永远不需要或想要使用这个类,除非存在 必须调用代码并传递标准的 JDBC接口实现。在 在这种情况下,此代码可能可用,但正在参与 Spring 托管 交易。可以使用更高级别编写新代码 前面提到的抽象。​​DataSource​

1.4. 声明式事务管理

Spring 框架的声明式事务管理可以通过 Spring 实现 面向方面的编程 (AOP)。但是,随着事务方面的代码出现 与 Spring 框架发行版一起使用,可以以样板方式使用 AOP 通常不必理解概念即可有效使用此代码。

Spring 框架的声明式事务管理类似于 EJB CMT,因为它 您可以指定事务行为(或缺少事务行为)到单个方法级别。 您可以在事务上下文中进行 acall,如果 必要。两种类型的事务管理之间的区别是:​​setRollbackOnly()​

  • 与与JTA绑定的EJB CMT不同,Spring Framework的声明式事务。 管理适用于任何环境。它可以与JTA事务或本地 使用 JDBC、JPA 或休眠通过调整配置进行事务 文件。
  • 您可以将 Spring 框架声明式事务管理应用于任何类, 不仅仅是像EJB这样的特殊类。
  • Spring 框架提供了声明式回滚规则,这是一个没有 EJB 的特性 等效。提供对回滚规则的编程和声明性支持。
  • Spring 框架允许您使用 AOP 自定义事务行为。 例如,您可以在事务回滚的情况下插入自定义行为。你 还可以添加任意建议以及事务性建议。使用 EJB CMT,您可以 不能影响容器的事务管理,除非 。setRollbackOnly()
  • Spring 框架不支持跨事务上下文的传播 远程调用,就像高端应用程序服务器一样。如果您需要此功能,我们 建议您使用 EJB。但是,在使用此类功能之前,请仔细考虑, 因为,通常情况下,人们不希望事务跨越远程调用。

回滚规则的概念很重要。它们允许您指定哪些例外 (和可抛掷对象)应导致自动回滚。您可以在 配置,而不是在 Java 代码中。所以,虽然你仍然可以打电话 对象回滚当前事务,最常见的是 可以指定必须始终导致回滚的规则。这 此选项的显著优点是业务对象不依赖于 事务基础结构。例如,他们通常不需要导入Spring。 事务 API 或其他 Spring API。​​setRollbackOnly()​​​​TransactionStatus​​​​MyApplicationException​

尽管 EJB 容器缺省行为会自动回滚 系统异常(通常是运行时异常),EJB CMT 不会回滚 在应用程序异常(即已检查的异常)上自动执行事务 除此之外)。虽然 Spring 默认行为 声明式事务管理遵循 EJB 约定(回滚仅自动进行 在未经检查的异常中),自定义此行为通常很有用。​​java.rmi.RemoteException​

1.4.1. 理解 Spring 框架的声明式事务实现

仅仅告诉你用注释来注释你的类是不够的,添加到你的配置中, 并期望您了解这一切是如何工作的。为了提供更深入的理解,这 部分解释了 Spring 框架声明式事务的内部工作原理 交易相关问题背景下的基础设施。​​@Transactional​​​​@EnableTransactionManagement​

关于 Spring 框架的声明式要掌握的最重要的概念 事务支持是通过AOP 代理启用的,并且事务 建议由元数据(目前基于 XML 或注释)驱动。AOP的组合 使用事务元数据生成使用 ain 的 AOP 代理 结合适当的实现来驱动事务 围绕方法调用。​​TransactionInterceptor​​​​TransactionManager​

Spring 框架提供事务管理 命令式和响应式编程模型。拦截器检测所需的风味 通过检查方法返回类型进行事务管理。返回反应式的方法 诸如 Kotlin 的类型(或其中的子类型)有资格进行反应 事务管理。所有其他返回类型,包括使用 命令式事务管理。​​TransactionInterceptor​​​​Publisher​​​​Flow​​​​void​

事务管理风格会影响需要哪个事务管理器。祈使的 事务需要 A,而响应式事务使用实现。​​PlatformTransactionManager​​​​ReactiveTransactionManager​

下图显示了在事务代理上调用方法的概念视图:

Spring数据访问和数据访问层与业务或服务层之间的交互

1.4.2. 声明式事务实现示例

请考虑以下接口及其伴随的实现。此示例使用 andclasses 作为占位符,以便您可以专注于事务 不关注特定域模型的使用情况。就本例而言, TheClass 在每个实现方法的主体中抛出实例这一事实很好。该行为可让您看到 正在创建事务,然后回滚以响应实例。以下清单显示了界面:​​Foo​​​​Bar​​​​DefaultFooService​​​​UnsupportedOperationException​​​​UnsupportedOperationException​​​​FooService​

// the service interface that we want to make transactional

package x.y.service;

public interface FooService {

Foo getFoo(String fooName);

Foo getFoo(String fooName, String barName);

void insertFoo(Foo foo);

void updateFoo(Foo foo);

}

以下示例显示了上述接口的实现:

package x.y.service;

public class DefaultFooService implements FooService {

@Override
public Foo getFoo(String fooName) {
// ...
}

@Override
public Foo getFoo(String fooName, String barName) {
// ...
}

@Override
public void insertFoo(Foo foo) {
// ...
}

@Override
public void updateFoo(Foo foo) {
// ...
}
}

假设接口的前两种方法,并且,必须在事务的上下文中以只读方式运行 语义和其他方法,并且,必须 在具有读写语义的事务上下文中运行。以下 配置将在接下来的几段中详细说明:​​FooService​​​​getFoo(String)​​​​getFoo(String, String)​​​​insertFoo(Foo)​​​​updateFoo(Foo)​

<!-- from the file 'context.xml' -->
<?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">

<!-- this is the service object that we want to make transactional -->
<bean class="x.y.service.DefaultFooService"/>

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>

<!-- don't forget the DataSource -->
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>

<!-- similarly, don't forget the TransactionManager -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- other <bean/> definitions here -->

</beans>

检查上述配置。它假定您要创建一个服务对象, 底豆,事务性。要应用的事务语义已封装 在定义中。该定义读作“所有方法 从 ARE 开始在只读事务的上下文中运行,并且所有 其他方法是使用默认事务语义运行”。标签的属性设置为将驱动事务的bean的名称(在本例中为bean)。​​fooService​​​​<tx:advice/>​​​​<tx:advice/>​​​​get​​​​transaction-manager​​​​<tx:advice/>​​​​TransactionManager​​​​txManager​

该定义确保由 bean 定义的事务建议在程序中的适当点运行。首先,定义一个 与接口中定义的任何操作的执行相匹配的切入点 ().然后,您将切入点与 theby 使用 顾问。结果表明,在执行 a 时, 定义 by 的建议运行。​​<aop:config/>​​​​txAdvice​​​​FooService​​​​fooServiceOperation​​​​txAdvice​​​​fooServiceOperation​​​​txAdvice​

元素中定义的表达式是AspectJ切入点 表达。有关切入点的更多详细信息,请参阅AOP 部分 春天的表情。​​<aop:pointcut/>​

一个常见的要求是使整个服务层具有事务性。最好的方式 这样做是为了更改切入点表达式以匹配 服务层。以下示例演示如何执行此操作:

<aop:config>
<aop:pointcut expression="execution(* x.y.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
</aop:config>

现在我们已经分析了配置,您可能会问自己, “所有这些配置实际上有什么作用?”

前面显示的配置用于围绕对象创建事务代理 这是根据 Thebean 定义创建的。代理配置为 事务性建议,以便在代理上调用适当的方法时, 事务已启动、挂起、标记为只读等,具体取决于 与该方法关联的事务配置。考虑以下程序 该测试驱动前面显示的配置:​​fooService​

public final class Boot {

public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml");
FooService fooService = ctx.getBean(FooService.class);
fooService.insertFoo(new Foo());
}
}

运行上述程序的输出应类似于以下内容(Log4J 为清楚起见,来自 thePose by Theclass 方法的输出和堆栈跟踪已被截断):​​UnsupportedOperationException​​​​insertFoo(..)​​​​DefaultFooService​

<!-- the Spring container is starting up... -->
[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy for bean 'fooService' with 0 common interceptors and 1 specific interceptors

<!-- the DefaultFooService is actually proxied -->
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]

<!-- ... the insertFoo(..) method is now being invoked on the proxy -->
[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo

<!-- the transactional advice kicks in here... -->
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection [org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction

<!-- the insertFoo(..) method from DefaultFooService throws an exception... -->
[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should rollback on java.lang.UnsupportedOperationException
[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo due to throwable [java.lang.UnsupportedOperationException]

<!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback) -->
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@a53de4]
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
[DataSourceUtils] - Returning JDBC Connection to DataSource

Exception in thread "main" java.lang.UnsupportedOperationException at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
<!-- AOP infrastructure stack trace elements removed for clarity -->
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)

要使用反应式事务管理,代码必须使用反应式类型。

下面的清单显示了以前使用的修改版本,但是 这次代码使用反应式类型:​​FooService​

// the reactive service interface that we want to make transactional

package x.y.service;

public interface FooService {

Flux<Foo> getFoo(String fooName);

Publisher<Foo> getFoo(String fooName, String barName);

Mono<Void> insertFoo(Foo foo);

Mono<Void> updateFoo(Foo foo);

}

以下示例显示了上述接口的实现:

package x.y.service;

public class DefaultFooService implements FooService {

@Override
public Flux<Foo> getFoo(String fooName) {
// ...
}

@Override
public Publisher<Foo> getFoo(String fooName, String barName) {
// ...
}

@Override
public Mono<Void> insertFoo(Foo foo) {
// ...
}

@Override
public Mono<Void> updateFoo(Foo foo) {
// ...
}
}

命令式和响应式事务管理共享相同的事务语义 边界和事务属性定义。命令式的主要区别 反应式事务是后者的延迟性质。使用事务运算符修饰返回的反应式类型以开始和清理 事务。因此,调用事务反应式方法会延迟实际 对激活反应式处理的订阅类型的事务管理 类型。​​TransactionInterceptor​

反应式事务管理的另一个方面与数据转义有关,即 编程模型的自然结果。

命令性事务的方法返回值从事务方法返回 成功终止方法后,使部分计算的结果不会逃逸 方法闭包。

反应式事务方法返回一个反应式包装器类型,该类型表示 计算序列以及开始和完成计算的承诺。

Acan 可以在事务正在进行但不一定完成时发出数据。 因此,依赖于成功完成整个事务的方法需要 以确保调用代码中的完成和缓冲结果。​​Publisher​

1.4.3. 回滚声明式事务

上一节概述了如何为 类,通常是服务层类,在应用程序中以声明方式提供。本节 描述如何在简单的声明性中控制事务的回滚 XML 配置中的时尚。有关以声明方式控制回滚语义的详细信息 使用注释,请参阅@Transactional设置。​​@Transactional​

向 Spring 框架的事务基础结构指示的推荐方法 事务的工作要回滚是抛出一个代码 当前正在事务上下文中执行。Spring 框架的 事务基础结构代码在冒泡时捕获任何未处理的内容 调用堆栈,并确定是否将事务标记为回滚。​​Exception​​​​Exception​

在其默认配置中,Spring 框架的事务基础结构代码 仅在运行时、未经检查的异常情况下将事务标记为回滚。 也就是说,当抛出的异常是 的实例或子类时。 (默认情况下,实例也会导致回滚)。已检查的异常 从事务方法引发不会导致默认回滚 配置。​​RuntimeException​​​​Error​

您可以准确配置哪些类型将事务标记为回滚, 通过指定回滚规则包括已检查的异常。​​Exception​

回滚规则

回滚规则确定当给定异常 抛出,规则基于异常类型或异常模式。

回滚规则可以通过 theandattributes 在 XML 中配置,这允许将规则定义为模式。使用@Transactional时,回滚规则可能会 通过 /和/属性进行配置,这允许规则 分别基于异常类型或模式定义。​​rollback-for​​​​no-rollback-for​​​​rollbackFor​​​​noRollbackFor​​​​rollbackForClassName​​​​noRollbackForClassName​

使用异常类型定义回滚规则时,该类型将用于匹配 针对抛出的异常类型及其超类型,提供类型安全和 避免使用模式时可能发生的任何意外匹配。例如,一个 值将仅匹配抛出的异常 类型及其子类。​​jakarta.servlet.ServletException.class​​​​jakarta.servlet.ServletException​

使用例外模式定义回滚规则时,该模式可以是完全 异常类型的限定类名或完全限定类名的子字符串 (必须是 的子类),目前没有通配符支持。为 例如,一个值 oforwill 匹配及其子类。​​Throwable​​​​"jakarta.servlet.ServletException"​​​​"ServletException"​​​​jakarta.servlet.ServletException​

以下 XML 代码段演示如何为选中的、 应用程序特定类型,通过属性提供异常模式:​​Exception​​​​rollback-for​

<tx:advice  transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

如果您不希望在引发异常时回滚事务,您还可以 指定“无回滚”规则。下面的例子告诉 Spring 框架的 事务基础结构,即使在面对 未处理:​​InstrumentNotFoundException​

<tx:advice >
<tx:attributes>
<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

当 Spring 框架的事务基础结构捕获异常并查询 配置的回滚规则,以确定是否将事务标记为回滚, 最强的匹配规则获胜。因此,在以下配置的情况下,任何 除 an 以外的异常导致回滚 服务员交易:​​InstrumentNotFoundException​

<tx:advice >
<tx:attributes>
<tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
</tx:attributes>
</tx:advice>

还可以以编程方式指示所需的回滚。虽然简单,但这个过程 非常具有侵入性,并且将您的代码与 Spring 框架的事务紧密耦合 基础设施。下面的示例演示如何以编程方式指示必需的 反转:

爪哇岛

科特林

public void resolvePosition() {
try {
// some business logic...
} catch (NoProductInStockException ex) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}

强烈建议您使用声明性方法进行回滚(如果有的话) 可能。如果您绝对需要,可以使用编程回滚,但它 使用与实现基于 POJO 的干净架构背道而驰。

1.4.4. 为不同的 bean 配置不同的事务语义

考虑以下场景:您有许多服务层对象,并且您希望 对它们中的每一个应用完全不同的事务配置。你可以这样做 通过定义具有不同和属性值的不同元素。​​<aop:advisor/>​​​​pointcut​​​​advice-ref​

作为比较点,首先假设所有服务图层类都是 在根包中定义。使所有 bean 都是类的实例 在该包(或子包)中定义,并且名称以 with 结尾 默认事务配置,您可以编写以下内容:​​x.y.service​​​​Service​

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

<aop:config>

<aop:pointcut
expression="execution(* x.y.service..*Service.*(..))"/>

<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>

</aop:config>

<!-- these two beans will be transactional... -->
<bean class="x.y.service.DefaultFooService"/>
<bean class="x.y.service.extras.SimpleBarService"/>

<!-- ... and these two beans won't -->
<bean class="org.xyz.SomeService"/> <!-- (not in the right package) -->
<bean class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->

<tx:advice >
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- other transaction infrastructure beans such as a TransactionManager omitted... -->

</beans>

以下示例显示了如何使用完全不同的 Bean 配置两个不同的 bean 事务设置:

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

<aop:config>

<aop:pointcut
expression="execution(* x.y.service.*Service.*(..))"/>

<aop:pointcut
expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>

<aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>

<aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>

</aop:config>

<!-- this bean will be transactional (see the 'defaultServiceOperation' pointcut) -->
<bean class="x.y.service.DefaultFooService"/>

<!-- this bean will also be transactional, but with totally different transactional settings -->
<bean class="x.y.service.ddl.DefaultDdlManager"/>

<tx:advice >
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<tx:advice >
<tx:attributes>
<tx:method name="*" propagation="NEVER"/>
</tx:attributes>
</tx:advice>

<!-- other transaction infrastructure beans such as a TransactionManager omitted... -->

</beans>

1.4.5. <tx:建议/>设置

本节总结了可以使用以下命令指定的各种事务设置 标签。默认设置为:​​<tx:advice/>​​​​<tx:advice/>​

  • 传播设置为REQUIRED.
  • 隔离级别为DEFAULT.
  • 事务是读写的。
  • 事务超时默认为基础事务的默认超时 系统或无(如果不支持超时)。
  • 任何触发器回滚,任何选中的都不会。RuntimeExceptionException

您可以更改这些默认设置。下表总结了标签的各种属性 嵌套在标签中:​​<tx:method/>​​​​<tx:advice/>​​​​<tx:attributes/>​

表 1.<tx:方法/>设置

属性

必填?

违约

描述

​name​

是的

要与事务属性关联的方法名称。这 通配符 (*) 字符可用于关联同一事务属性 具有多种方法(例如,,,,等)的设置 四)。​​get*​​​​handle*​​​​on*Event​

​propagation​

​REQUIRED​

事务传播行为。

​isolation​

​DEFAULT​

事务隔离级别。仅适用于传播设置 ofor。​​REQUIRED​​​​REQUIRES_NEW​

​timeout​

-1

事务超时(秒)。仅适用于传播器。​​REQUIRED​​​​REQUIRES_NEW​

​read-only​

读写事务与只读事务。仅适用于 toor。​​REQUIRED​​​​REQUIRES_NEW​

​rollback-for​

以逗号分隔的触发回滚的实例列表。例如。​​Exception​​​​com.foo.MyBusinessException,ServletException​

​no-rollback-for​

以逗号分隔的不触发回滚的实例列表。例如。​​Exception​​​​com.foo.MyBusinessException,ServletException​

1.4.6. 使用​​@Transactional​

除了基于 XML 的事务配置声明性方法之外,您还可以 使用基于注释的方法。直接在 Java 中声明事务语义 源代码使声明更接近受影响的代码。没有多少 过度耦合的危险,因为用于事务性的代码是 无论如何,几乎总是以这种方式部署。

使用注释提供的易用性是最好的 用一个示例进行说明,该示例在下面的文本中进行了说明。 请考虑以下类定义:​​@Transactional​

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

@Override
public Foo getFoo(String fooName) {
// ...
}

@Override
public Foo getFoo(String fooName, String barName) {
// ...
}

@Override
public void insertFoo(Foo foo) {
// ...
}

@Override
public void updateFoo(Foo foo) {
// ...
}
}

使 Bean 实例具有事务性的行。

如上所述在类级别使用,注释指示所有方法的默认值 声明类(及其子类)。或者,每种方法都可以 单独注释。有关方法可见性和@Transactional 有关 Spring 认为哪些方法具有事务性的更多详细信息。请注意,类级别 注释不适用于类层次结构中的祖先类;在这种情况下, 继承的方法需要在本地重新声明才能参与 子类级别注释。

当像上面这样的 POJO 类被定义为 Spring 上下文中的 bean 时, 您可以通过 aclass 中的 anannotation 使 Bean 实例成为事务性实例。有关完整的详细信息,请参阅javadoc。​​@EnableTransactionManagement​​​​@Configuration​

在 XML 配置中,标记提供了类似的便利:​​<tx:annotation-driven/>​

<!-- from the file 'context.xml' -->
<?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">

<!-- this is the service object that we want to make transactional -->
<bean class="x.y.service.DefaultFooService"/>

<!-- enable the configuration of transactional behavior based on annotations -->
<!-- a TransactionManager is still required -->
<tx:annotation-driven transaction-manager="txManager"/>

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- other <bean/> definitions here -->

</beans>

与命令式相反,反应式事务方法使用反应式返回类型 编程安排如下表所示:

// the reactive service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

@Override
public Publisher<Foo> getFoo(String fooName) {
// ...
}

@Override
public Mono<Foo> getFoo(String fooName, String barName) {
// ...
}

@Override
public Mono<Void> insertFoo(Foo foo) {
// ...
}

@Override
public Mono<Void> updateFoo(Foo foo) {
// ...
}
}

请注意,对于返回的 反应流取消信号。请参阅下面的取消信号部分 “使用事务运算符”以获取更多详细信息。​​Publisher​

方法可见性和​​@Transactional​

当您使用具有 Spring 标准配置的事务代理时,您应该应用 仅对具有可见性的方法进行注释。如果你这样做 注释,或包可见的方法 使用注释,不会引发错误,但注释方法不显示已配置的 事务设置。如果需要注释非公共方法,请考虑中的提示 以下段落用于基于类的代理或考虑使用 AspectJ 编译时或 加载时编织(稍后描述)。​​@Transactional​​​​public​​​​protected​​​​private​​​​@Transactional​

在类中使用时,或 包可见的方法也可以通过以下方式为基于类的代理提供事务性 注册自定义Bean,如以下示例所示。 但请注意,基于接口的代理中的事务方法必须始终在代理接口中定义。​​@EnableTransactionManagement​​​​@Configuration​​​​protected​​​​transactionAttributeSource​​​​public​

Spring TestContext Framework通过以下方式支持非私有测试方法 违约。请参阅测试中的事务管理 章节为例。​​@Transactional​

/**
* Register a custom AnnotationTransactionAttributeSource with the
* publicMethodsOnly flag set to false to enable support for
* protected and package-private @Transactional methods in
* class-based proxies.
*
* @see ProxyTransactionManagementConfiguration#transactionAttributeSource()
*/
@Bean
TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource(false);
}

您可以将注释应用于接口定义,一种方法 在接口、类定义或类上的方法上。然而, 仅仅存在注释不足以激活 事务行为。注释只是元数据,可以 被一些感知的运行时基础结构使用,并且 可以使用元数据来配置具有事务行为的相应 Bean。 在前面的示例中,元素打开 事务行为。​@Transactional​​​​@Transactional​​​​@Transactional​​​​@Transactional​​​​<tx:annotation-driven/>​

请考虑使用 AspectJ 模式(请参阅下表中的属性),如果您 期望自我调用也与事务一起包装。在这种情况下,有 首先没有代理。相反,目标类是编织的(即,它的字节码 修改)以支持任何类型的方法上的运行时行为。​​mode​​​​@Transactional​

表 2.注释驱动的事务设置

XML 属性

注释属性

违约

描述

​transaction-manager​

N/A (参见TransactionManagementConfigurerjavadoc)

​transactionManager​

要使用的事务管理器的名称。仅当事务名称时才需要 管理器不是,如前面的示例所示。​​transactionManager​

​mode​

​mode​

​proxy​

默认模式 () 使用 Spring 的 AOP 处理要代理的带注释的 bean 框架(遵循代理语义,如前所述,应用于方法调用 仅通过代理进入)。替代模式 () 相反,编织了 受影响的类与 Spring 的 AspectJ 事务方面,修改目标类 应用于任何类型的方法调用的字节码。AspectJ 编织要求在类路径中以及具有加载时编织(或编译时) 编织)启用。(有关如何设置加载时间编织的详细信息,请参见Spring 配置​。​​proxy​​​​aspectj​​​​spring-aspects.jar​

​proxy-target-class​

​proxyTargetClass​

​false​

仅适用于模式。控制创建哪种类型的事务代理 对于用注释注释的类。如果属性设置为 ,则创建基于类的代理。 如果省略该属性,则为标准 JDK 创建基于接口的代理。(有关不同代理类型的详细检查,请参阅代理机制​。​​proxy​​​​@Transactional​​​​proxy-target-class​​​​true​​​​proxy-target-class​​​​false​

​order​

​order​

​Ordered.LOWEST_PRECEDENCE​

定义应用于注释的 bean 的事务通知的顺序。(有关 AOP 排序相关规则的更多信息 建议,请参阅建议排序​。 没有指定的顺序意味着 AOP 子系统确定建议的顺序。​​@Transactional​

在评估事务设置时,派生位置最多优先 对于方法。在以下示例中,类是 在类级别使用只读事务的设置进行注释,但对同一类中的方法进行注释需要 优先于在类级别定义的事务设置。​​DefaultFooService​​​​@Transactional​​​​updateFoo(Foo)​

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

public Foo getFoo(String fooName) {
// ...
}

// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// ...
}
}
​@Transactional​​设置

注释是指定接口、类、 或方法必须具有事务语义(例如,“启动全新的只读 调用此方法时的事务,暂停任何现有事务“)。 默认设置如下:​​@Transactional​​​​@Transactional​

  • 传播设置为PROPAGATION_REQUIRED.
  • 隔离级别为ISOLATION_DEFAULT.
  • 事务是读写的。
  • 事务超时默认为基础事务的默认超时 系统,如果不支持超时,则为无。
  • 任何触发器回滚,以及任何选中的回滚 不。RuntimeExceptionErrorException

您可以更改这些默认设置。下表总结了各种 注释的属性:​​@Transactional​

表 3.@Transactional设置

财产

类型

描述

价值

​String​

指定要使用的事务管理器的可选限定符。

​transactionManager​

​String​

别名。​​value​

​label​

用于向事务添加富有表现力的描述的标签数组。​​String​

事务管理器可以评估标签,以将特定于实现的行为与实际事务相关联。

增殖

​enum​​​: ​​Propagation​

可选的传播设置。

​isolation​

​enum​​​: ​​Isolation​

可选隔离级别。仅适用于传播值 ofor。​​REQUIRED​​​​REQUIRES_NEW​

​timeout​

​int​​(以秒为单位)

可选的事务超时。仅适用于传播值 ofor。​​REQUIRED​​​​REQUIRES_NEW​

​timeoutString​

​String​​(以秒为单位)

将秒数指定为值的替代方法,例如,作为占位符。​​timeout​​​​String​

​readOnly​

​boolean​

读写事务与只读事务。仅适用于值 ofor。​​REQUIRED​​​​REQUIRES_NEW​

​rollbackFor​

对象数组,必须派生自​​Class​​​​Throwable.​

必须导致回滚的异常类型的可选数组。

​rollbackForClassName​

异常名称模式数组。

必须导致回滚的异常名称模式的可选数组。

​noRollbackFor​

对象数组,必须派生自​​Class​​​​Throwable.​

不得导致回滚的异常类型的可选数组。

​noRollbackForClassName​

异常名称模式数组。

不得导致回滚的异常名称模式的可选数组。

目前,您无法显式控制事务的名称,其中“名称” 表示事务监视器中显示的事务名称(如果适用) (例如,WebLogic 的事务监视器),并在日志记录输出中。对于声明性 事务,事务名称始终是完全限定的类名 ++ 事务建议类的方法名称。例如,如果类的方法启动了一个事务,则 事务的名称将是:。​​.​​​​handlePayment(..)​​​​BusinessService​​​​com.example.BusinessService.handlePayment​

多个事务管理器​​@Transactional​

大多数 Spring 应用程序只需要一个事务管理器,但可能存在 您希望在单个事务管理器中具有多个独立事务管理器的情况 应用。您可以使用注释的 theorattribute 来选择性地指定要使用的标识。这可以是 Bean 名称或限定符值 的事务管理器 Bean。例如,使用限定符表示法,您可以 将以下 Java 代码与以下事务管理器 Bean 声明相结合 在应用程序上下文中:​​value​​​​transactionManager​​​​@Transactional​​​​TransactionManager​

public class TransactionalService {

@Transactional("order")
public void setSomething(String name) { ... }

@Transactional("account")
public void doSomething() { ... }

@Transactional("reactive-account")
public Mono<Void> doSomethingReactive() { ... }
}

以下清单显示了 Bean 声明:

<tx:annotation-driven/>

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
...
<qualifier value="order"/>
</bean>

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
...
<qualifier value="account"/>
</bean>

<bean class="org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager">
...
<qualifier value="reactive-account"/>
</bean>

在这种情况下,各个方法在单独的 事务管理器,由 、 和限定符区分。默认目标 Bean 名称,, 如果未找到特定限定的 Bean,则仍使用。​​TransactionalService​​​​order​​​​account​​​​reactive-account​​​​<tx:annotation-driven>​​​​transactionManager​​​​TransactionManager​

自定义撰写批注

如果你发现你反复使用相同的属性和许多不同的 方法,Spring的元标注支持让你 为您的特定用例定义自定义组合注释。例如,考虑 以下注释定义:​​@Transactional​

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(transactionManager = "order", label = "causal-consistency")
public @interface OrderTx {
}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(transactionManager = "account", label = "retryable")
public @interface AccountTx {
}

前面的注释让我们编写上一节中的示例,如下所示:

public class TransactionalService {

@OrderTx
public void setSomething(String name) {
// ...
}

@AccountTx
public void doSomething() {
// ...
}
}

在前面的示例中,我们使用语法来定义事务管理器限定符 和事务标签,但我们也可以包括传播行为, 回滚规则、超时和其他功能。

1.4.7. 事务传播

本节介绍 Spring 中事务传播的一些语义。注意 本节不是对事务传播的正确介绍。相反,它 详细介绍了 Spring 中有关事务传播的一些语义。

在 Spring 管理的交易中,请注意物理和 逻辑事务,以及传播设置如何应用于此差异。

理解​​PROPAGATION_REQUIRED​

Spring数据访问和数据访问层与业务或服务层之间的交互

​PROPAGATION_REQUIRED​​强制实施物理事务,无论是本地的当前 范围,如果尚不存在事务或参与现有的“外部”事务 为更大的范围定义。这是常见调用堆栈安排中的良好默认值 在同一线程中(例如,委托给多个存储库方法的服务外观 其中所有底层资源都必须参与服务级别事务)。

当传播设置为逻辑事务范围时 为应用设置的每个方法创建。每个这样的逻辑 事务范围可以单独确定仅回滚状态,具有外部 事务范围在逻辑上独立于内部事务范围。 在标准行为的情况下,所有这些作用域都是 映射到同一物理事务。因此,在内部设置了仅回滚标记 事务范围确实会影响外部事务实际提交的机会。​​PROPAGATION_REQUIRED​​​​PROPAGATION_REQUIRED​

但是,在内部事务范围设置仅回滚标记的情况下, 外部事务尚未决定回滚本身,因此回滚(静默 由内部事务范围触发)是意外的。一个对应的是抛出的那个点。这是预期行为,因此 事务的调用方永远不会被误导,认为提交是 当它真的不是时执行。因此,如果一个内部事务(其中外部调用者 不知道)静默地将事务标记为仅回滚,外部调用方仍然 调用提交。外部调用方需要接收 anto 清楚地指示已执行回滚。​​UnexpectedRollbackException​​​​UnexpectedRollbackException​

理解​​PROPAGATION_REQUIRES_NEW​

Spring数据访问和数据访问层与业务或服务层之间的交互

​PROPAGATION_REQUIRES_NEW​​​,相反,始终使用 每个受影响的事务范围的独立物理事务,从不 参与外部范围的现有事务。在这样的安排下, 基础资源事务是不同的,因此可以提交或回滚 独立,外部事务不受内部事务回滚的影响 状态,并在内部事务完成后立即释放其锁。 这样独立的内部事务还可以声明自己的隔离级别、超时、 和只读设置,并且不继承外部事务的特征。​​PROPAGATION_REQUIRED​

理解​​PROPAGATION_NESTED​

​PROPAGATION_NESTED​​使用具有多个保存点的单个物理事务 它可以回滚到。这种部分回滚允许内部事务范围 触发其范围的回滚,外部事务能够继续 尽管某些操作已回滚,但物理事务。此设置 通常映射到 JDBC 保存点,因此它仅适用于 JDBC 资源 交易。请参阅 Spring 的DataSourceTransactionManager。

1.4.8. 为交易操作提供建议

假设您要同时运行事务操作和一些基本的分析建议。 您如何在上下文中对此产生影响?​​<tx:annotation-driven/>​

调用该方法时,希望看到以下操作:​​updateFoo(Foo)​

  • 配置的分析方面将启动。
  • 事务性建议运行。
  • 建议对象上的方法将运行。
  • 事务提交。
  • 分析方面报告整个事务方法调用的确切持续时间。

以下代码显示了前面讨论的简单性能分析方面:

package x.y;

public class SimpleProfiler implements Ordered {

private int order;

// allows us to control the ordering of advice
public int getOrder() {
return this.order;
}

public void setOrder(int order) {
this.order = order;
}

// this method is the around advice
public Object profile(ProceedingJoinPoint call) throws Throwable {
Object returnValue;
StopWatch clock = new StopWatch(getClass().getName());
try {
clock.start(call.toShortString());
returnValue = call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
return returnValue;
}
}

建议的顺序 通过接口进行控制。有关建议排序的完整详细信息,请参阅建议排序。​​Ordered​

以下配置创建具有分析和 按所需顺序应用于它的事务方面:​​fooService​

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

<bean class="x.y.service.DefaultFooService"/>

<!-- this is the aspect -->
<bean class="x.y.SimpleProfiler">
<!-- run before the transactional advice (hence the lower order number) -->
<property name="order" value="1"/>
</bean>

<tx:annotation-driven transaction-manager="txManager" order="200"/>

<aop:config>
<!-- this advice runs around the transactional advice -->
<aop:aspect ref="profiler">
<aop:pointcut
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
</aop:aspect>
</aop:config>

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

</beans>

您可以配置任何号码 以类似的方式进行的其他方面。

下面的示例创建与前两个示例相同的设置,但使用纯 XML 声明性方法:

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

<bean class="x.y.service.DefaultFooService"/>

<!-- the profiling advice -->
<bean class="x.y.SimpleProfiler">
<!-- run before the transactional advice (hence the lower order number) -->
<property name="order" value="1"/>
</bean>

<aop:config>
<aop:pointcut expression="execution(* x.y..*Service.*(..))"/>
<!-- runs after the profiling advice (cf. the order attribute) -->

<aop:advisor advice-ref="txAdvice" pointcut-ref="entryPointMethod" order="2"/>
<!-- order value is higher than the profiling aspect -->

<aop:aspect ref="profiler">
<aop:pointcut
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
</aop:aspect>

</aop:config>

<tx:advice transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- other <bean/> definitions such as a DataSource and a TransactionManager here -->

</beans>

上述配置的结果是具有分析和 事务方面按该顺序应用于它。如果您需要分析建议 在交易建议之后运行 交易建议 在出路时,您可以交换分析的价值 方面豆的属性,使其高于交易建议的 订单价值。​​fooService​​​​order​

您可以以类似的方式配置其他方面。

1.4.9. 与方面J一起使用​​@Transactional​

你也可以在Spring之外使用Spring Framework的支持。 容器通过AspectJ方面。为此,请先为课程添加批注 (以及可选的类的方法)与注释, 然后将您的应用程序与文件中定义的应用程序链接(编织)。您还必须使用事务配置方面 经理。你可以使用 Spring 框架的 IoC 容器来处理 依赖注入方面。配置事务的最简单方法 管理方面是使用元素并指定属性 toas 中所述@Transactional。因为 我们在这里重点介绍在 Spring 容器之外运行的应用程序,我们展示 你如何以编程方式做到这一点。​​@Transactional​​​​@Transactional​​​​org.springframework.transaction.aspectj.AnnotationTransactionAspect​​​​spring-aspects.jar​​​​<tx:annotation-driven/>​​​​mode​​​​aspectj​

下面的示例演示如何创建事务管理器并配置使用它:​​AnnotationTransactionAspect​

// construct an appropriate transaction manager
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());

// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);

类上的注释指定默认事务语义 用于执行类中的任何公共方法。​​@Transactional​

类中方法的注释将覆盖默认值 由类注释(如果存在)给出的事务语义。您可以注释任何方法, 无论能见度如何。​​@Transactional​

要编织您的应用程序,您必须构建 您使用AspectJ的应用程序(请参阅AspectJ开发 指南)或使用加载时间编织。请参阅加载时编织 Spring 框架中的AspectJ 讨论使用 AspectJ 进行加载时间编织。​​AnnotationTransactionAspect​

1.5. 程序化交易管理

Spring 框架提供了两种编程事务管理方法,方法是:

  • 理论。TransactionTemplateTransactionalOperator
  • 直接实施。TransactionManager

春季团队通常推荐用于程序化 命令式流和响应式代码中的事务管理。 第二种方法类似于使用 JTAAPI,尽管有例外 处理不那么麻烦。​​TransactionTemplate​​​​TransactionalOperator​​​​UserTransaction​

1.5.1. 使用​​TransactionTemplate​

采用与其他 Spring 模板相同的方法,例如 这。它使用回调方法(将应用程序代码从 执行样板获取并释放事务资源)并导致 意图驱动的代码,因为您的代码只关注什么 你想做。​​TransactionTemplate​​​​JdbcTemplate​

必须在事务上下文中运行并显式使用下一个示例的应用程序代码。您,作为应用程序 开发人员,可以编写一个实现(通常表示为 匿名内部类),其中包含需要在 一个事务。然后,您可以传递在 上公开的自定义方法的实例。以下示例演示如何执行此操作:​​TransactionTemplate​​​​TransactionCallback​​​​TransactionCallback​​​​execute(..)​​​​TransactionTemplate​

public class SimpleService implements Service {

// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;

// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}

public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method runs in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}

如果没有返回值,可以使用 方便类 使用匿名类,如下所示:​​TransactionCallbackWithoutResult​

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});

回调中的代码可以通过调用提供的对象的方法来回滚事务,如下所示:​​setRollbackOnly()​​​​TransactionStatus​

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
指定事务设置

您可以指定事务设置(例如传播模式、隔离级别、 超时等)以编程方式或在 配置。默认情况下,实例具有默认的事务设置。这 以下示例显示了 的事务设置的编程自定义 一个特定的​​TransactionTemplate​​​​TransactionTemplate​​​​TransactionTemplate:​

public class SimpleService implements Service {

private final TransactionTemplate transactionTemplate;

public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);

// the transaction settings can be set here explicitly if so desired
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 seconds
// and so forth...
}
}

以下示例使用一些自定义事务定义 使用 Spring XML 配置进行设置:​​TransactionTemplate​

<bean 
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>

然后,您可以根据需要注入任意数量的服务。​​sharedTransactionTemplate​

最后,类的实例是线程安全的,在该实例中 不维护任何会话状态。但是,实例可以维护 维护配置状态。因此,虽然许多类可以共享一个实例 的,如果一个类需要使用 awith 不同的设置(例如,不同的隔离级别),您需要创建 两个不同的实例。​​TransactionTemplate​​​​TransactionTemplate​​​​TransactionTemplate​​​​TransactionTemplate​​​​TransactionTemplate​

1.5.2. 使用​​TransactionalOperator​

遵循类似于其他反应式的操作员设计 运营商。它使用回调方法(将应用程序代码从执行 样板获取和发布事务资源),并生成 意图驱动,因为你的代码只关注你想要做的事情。​​TransactionalOperator​

必须在事务上下文中运行且显式使用的应用程序代码 下面是下一个示例:​​TransactionalOperator​

爪哇岛

科特林

public class SimpleService implements Service {

// single TransactionalOperator shared amongst all methods in this instance
private final TransactionalOperator transactionalOperator;

// use constructor-injection to supply the ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionalOperator = TransactionalOperator.create(transactionManager);
}

public Mono<Object> someServiceMethod() {

// the code in this method runs in a transactional context

Mono<Object> update = updateOperation1();

return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
}
}

​TransactionalOperator​​可以通过两种方式使用:

  • 使用项目反应器类型 (mono.as(transactionalOperator::transactional))
  • 其他所有情况的回调样式 (transactionalOperator.execute(TransactionCallback<T>))

回调中的代码可以通过调用提供的对象的方法来回滚事务,如下所示:​​setRollbackOnly()​​​​ReactiveTransaction​

爪哇岛

科特林

transactionalOperator.execute(new TransactionCallback<>() {

public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
取消信号

在反应流中,acan 可以取消它的 ss并停止它。Project Reactor 以及其他库中的操作员(例如,,, 和其他人)可以发布取消。没有办法 了解取消的原因,无论是由于错误还是仅仅是由于缺乏 兴趣进一步消费。从版本 5.3 开始,取消信号会导致回滚。 因此,重要的是要考虑交易下游使用的运算符。特别是在aor或其他多值的情况下, 必须使用完整输出才能完成事务。​​Subscriber​​​​Subscription​​​​Publisher​​​​next()​​​​take(long)​​​​timeout(Duration)​​​​Publisher​​​​Flux​​​​Publisher​

指定事务设置

您可以指定事务设置(例如传播模式、隔离级别、 超时,依此类推)。默认情况下,实例具有默认事务设置。这 以下示例显示了特定事务设置的自定义​​TransactionalOperator​​​​TransactionalOperator​​​​TransactionalOperator:​

public class SimpleService implements Service {

private final TransactionalOperator transactionalOperator;

public SimpleService(ReactiveTransactionManager transactionManager) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();

// the transaction settings can be set here explicitly if so desired
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
definition.setTimeout(30); // 30 seconds
// and so forth...

this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
}
}

1.5.3. 使用​​TransactionManager​

以下部分解释命令式事务和反应式事务的编程用法 经理。

使用​​PlatformTransactionManager​

对于命令式事务,您可以直接使用 来管理您的 交易。为此,请通过您的实施 通过 Bean 引用用于您的 Bean。然后,通过使用 theandobjects,您可以启动事务、回滚和提交。这 以下示例演示如何执行此操作:​​org.springframework.transaction.PlatformTransactionManager​​​​PlatformTransactionManager​​​​TransactionDefinition​​​​TransactionStatus​

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
// put your business logic here
} catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
使用​​ReactiveTransactionManager​

使用反应式事务时,您可以直接使用 来管理您的 交易。为此,请通过您的实施 通过 Bean 引用用于您的 Bean。然后,通过使用 theandobjects,您可以启动事务、回滚和提交。这 以下示例演示如何执行此操作:​​org.springframework.transaction.ReactiveTransactionManager​​​​ReactiveTransactionManager​​​​TransactionDefinition​​​​ReactiveTransaction​

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);

reactiveTx.flatMap(status -> {

Mono<Object> tx = ...; // put your business logic here

return tx.then(txManager.commit(status))
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});

1.6. 在程序化和声明式事务管理之间进行选择

程序化事务管理通常是一个好主意,只有当你有一个小 事务操作数。例如,如果您有一个 Web 应用程序 仅对某些更新操作需要事务,您可能不想设置 使用 Spring 或任何其他技术的交易代理。在这种情况下,使用可能是一个很好的方法。能够设置交易名称 显式也是只能通过使用编程方法才能完成的事情 到事务管理。​​TransactionTemplate​

另一方面,如果应用程序具有大量事务操作, 声明式事务管理通常是值得的。它保持交易 管理脱离业务逻辑,配置起来并不困难。使用 Spring Framework,而不是 EJB CMT,声明式事务的配置成本 管理大大减少。

1.7. 交易绑定事件

从 Spring 4.2 开始,事件的侦听器可以绑定到事务的某个阶段。 典型的示例是在事务成功完成时处理事件。 这样做可以让事件在当前结果时更灵活地使用 事务实际上对侦听器很重要。

您可以使用注释注册常规事件侦听器。 如果需要将其绑定到事务,请使用。 执行此操作时,默认情况下侦听器绑定到事务的提交阶段。​​@EventListener​​​​@TransactionalEventListener​

下一个示例演示了此概念。假设组件发布订单创建 事件,并且我们想要定义一个侦听器,该侦听器应该只处理该事件一次 已发布它的事务已成功提交。以下 示例设置这样的事件侦听器:

@Component
public class MyComponent {

@TransactionalEventListener
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
// ...
}
}

Theannotation 公开了一个属性,让你 自定义侦听器应绑定到的事务阶段。 有效阶段是(默认)以及聚合事务完成的阶段(无论是提交还是回滚)。​​@TransactionalEventListener​​​​phase​​​​BEFORE_COMMIT​​​​AFTER_COMMIT​​​​AFTER_ROLLBACK​​​​AFTER_COMPLETION​

如果没有事务正在运行,则根本不调用侦听器,因为我们无法遵循 必需的语义。但是,您可以通过将批注的属性设置为来覆盖该行为。​​fallbackExecution​​​​true​


​@TransactionalEventListener​​​仅适用于由 管理的线程绑定事务。由 Reactor 上下文而不是线程本地属性管理的反应式事务,因此从 事件侦听器,则没有可以参与的兼容活动事务。​​PlatformTransactionManager​​​​ReactiveTransactionManager​


1.8. 特定于应用程序服务器的集成

Spring 的事务抽象通常与应用程序服务器无关。此外 Spring'sclass(可以选择性地执行 JNDI 查找 JTAand对象)自动检测位置 后一个对象,因应用程序服务器而异。访问 JTA 可以增强事务语义 — 特别是, 支持交易暂停。有关详细信息,请参阅JtaTransactionManagerjavadoc。​​JtaTransactionManager​​​​UserTransaction​​​​TransactionManager​​​​TransactionManager​

Spring's是运行Jakarta EE应用程序的标准选择 服务器,并且已知可在所有常见服务器上工作。高级功能,例如 交易暂停,也适用于许多服务器(包括GlassFish,JBoss和 杰罗尼莫),无需任何特殊配置。但是,对于完全支持 交易暂停和进一步的高级集成,Spring 包括特殊的适配器 适用于 WebLogic Server 和 WebSphere。下面将讨论这些适配器 部分。​​JtaTransactionManager​

对于标准方案,包括 WebLogic Server 和 WebSphere,请考虑使用 方便的配置元素。配置后, 此元素会自动检测底层服务器并选择最佳 可用于平台的事务管理器。这意味着您不需要明确 配置特定于服务器的适配器类(如以下各节所述)。 相反,它们是自动选择的,标准作为默认回退。​​<tx:jta-transaction-manager/>​​​​JtaTransactionManager​

1.8.1. IBM WebSphere

在 WebSphere 6.1.0.9 及更高版本上,建议使用的 Spring JTA 事务管理器是。这个特殊的适配器使用 IBM 的 API, 在 WebSphere Application Server 6.1.0.9 及更高版本中可用。使用此适配器, Spring 驱动的事务暂停(由发起者暂停和恢复)由 IBM 正式支持。​​WebSphereUowTransactionManager​​​​UOWManager​​​​PROPAGATION_REQUIRES_NEW​

1.8.2. Oracle WebLogic Server

在 WebLogic Server 9.0 或更高版本上,您通常会使用 the,而不是 stockclass。这 normal的特殊WebLogic特定子类支持: Spring 的事务定义在 WebLogic 管理的事务中的全部功能 环境,超越标准 JTA 语义。功能包括交易名称, 每个事务的隔离级别,并在所有情况下正确恢复事务。​​WebLogicJtaTransactionManager​​​​JtaTransactionManager​​​​JtaTransactionManager​

1.9. 常见问题的解决方案

本节介绍一些常见问题的解决方案。

1.9.1. 对特定事务管理器使用错误的事务管理器​​DataSource​

根据您选择的 事务技术和要求。正确使用,Spring 框架仅 提供简单且可移植的抽象。如果使用全局 事务,您必须使用类(或特定于应用程序服务器的子类 it) 用于您的所有事务操作。否则,事务基础结构 尝试对容器实例等资源执行本地事务。这样的本地事务没有意义,一个好的应用服务器 将它们视为错误。​​PlatformTransactionManager​​​​org.springframework.transaction.jta.JtaTransactionManager​​​​DataSource​

1.10. 更多资源

有关 Spring 框架的事务支持的更多信息,请参阅:

  • 分散式 Spring中的事务,有和没有XA是一个JavaWorld演示,其中 Spring的David Syer将引导您了解分布式的七种模式 Spring 应用程序中的事务,其中三个带有 XA,四个没有。
  • 《Java事务设计策略》​是一本书 可从InfoQ获得,提供节奏良好的介绍 到爪哇中的事务。它还包括有关如何配置的并行示例 并使用 Spring 框架和 EJB3 的事务。