此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.0spring-doc.cadn.net.cn

@Transactional

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

标准jakarta.transaction.Transactionalannotation 也支持作为 Spring 自己的 Comments 的直接替代品。请参阅 JTA 文档 了解更多详情。

使用@Transactional注释是最好的 用一个例子来说明,这将在下面的文本中解释。 请考虑以下类定义:spring-doc.cadn.net.cn

// 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) {
		// ...
	}
}
// the service class that we want to make transactional
@Transactional
class DefaultFooService : FooService {

	override fun getFoo(fooName: String): Foo {
		// ...
	}

	override fun getFoo(fooName: String, barName: String): Foo {
		// ...
	}

	override fun insertFoo(foo: Foo) {
		// ...
	}

	override fun updateFoo(foo: Foo) {
		// ...
	}
}

如上所述,在类级别使用,注释表示所有方法的默认值 声明类(及其子类)的 Statementing Class。或者,每种方法都可以是 单独注释。有关 Spring 认为哪些方法为事务的更多详细信息,请参见方法可见性。请注意,类级别 annotation 不适用于 class 层次结构中的祖先类;在这种情况下, 继承的方法需要在本地重新声明才能参与 subclass-level 注解。spring-doc.cadn.net.cn

当 POJO 类(如上面的类)在 Spring 上下文中被定义为 bean 时, 您可以通过@EnableTransactionManagement注解@Configuration类。有关完整详细信息,请参阅 javadocspring-doc.cadn.net.cn

在 XML 配置中,<tx:annotation-driven/>标签提供了类似的便利:spring-doc.cadn.net.cn

<!-- 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 id="fooService" 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"/> (1)

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

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

</beans>
1 使 Bean 实例成为事务性的行。
您可以省略transaction-manager属性中的<tx:annotation-driven/>tag 的TransactionManager的名称为transactionManager.如果TransactionManager你想要依赖注入的 bean 具有任何其他名称,则必须使用transaction-manager属性,如 前面的示例。

与命令式相反,反应式事务方法使用反应式返回类型 编程安排如下 清单所示:spring-doc.cadn.net.cn

// 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) {
		// ...
	}
}
// the reactive service class that we want to make transactional
@Transactional
class DefaultFooService : FooService {

	override fun getFoo(fooName: String): Flow<Foo> {
		// ...
	}

	override fun getFoo(fooName: String, barName: String): Mono<Foo> {
		// ...
	}

	override fun insertFoo(foo: Foo): Mono<Void> {
		// ...
	}

	override fun updateFoo(foo: Foo): Mono<Void> {
		// ...
	}
}

请注意,对于返回的Publisher关于 Reactive Streams 取消信号。有关更多详细信息,请参阅“使用 TransactionalOperator”下的 Cancel Signals 部分。spring-doc.cadn.net.cn

方法 visibility 和@Transactional在代理模式下

@Transactional注解通常用于public能见度。 从 6.0 开始,protected或者包可见的方法也可以为 默认基于类的代理。请注意,基于接口的 代理必须始终为public并在 proxied interface中定义。对于两种 的代理,只有通过代理传入的外部方法调用才会被拦截。spring-doc.cadn.net.cn

如果您希望对不同类型方法的可见性进行一致的处理 proxies(在 5.3 之前是默认值),请考虑指定publicMethodsOnly:spring-doc.cadn.net.cn

/**
 * Register a custom AnnotationTransactionAttributeSource with the
 * publicMethodsOnly flag set to true to consistently ignore non-public methods.
 * @see ProxyTransactionManagementConfiguration#transactionAttributeSource()
 */
@Bean
TransactionAttributeSource transactionAttributeSource() {
	return new AnnotationTransactionAttributeSource(true);
}

Spring TestContext 框架支持非私有@Transactional测试方法 默认情况下也是如此。有关示例,请参阅 testing 章节中的 Transaction Managementspring-doc.cadn.net.cn

您可以应用@Transactional对接口定义的注解、方法 在接口、类定义或类上的方法上。然而,仅仅存在 的@Transactionalannotation 不足以激活事务行为。 这@Transactionalannotation 只是元数据,可以由相应的 运行时基础结构,该基础结构使用该元数据来配置适当的 bean 交易行为。在前面的示例中,<tx:annotation-driven/>元素 在运行时打开实际事务管理。spring-doc.cadn.net.cn

Spring 团队建议您使用@Transactional注解,而不是依赖接口中带注解的方法, 即使后者在 5.0 中确实适用于基于接口的代理和 Target 类代理。 由于 Java 注解不是从接口继承的,因此接口声明的注解 在使用 AspectJ 模式时仍然无法被 weaveing 基础设施识别,因此 aspect 不会被应用。因此,您的交易注释可能是 静默忽略:在您测试回滚方案之前,您的代码可能看起来“有效”。
在代理模式(这是默认模式)下,只有外部方法调用通过 代理被拦截。这意味着自调用(实际上是 target 对象调用 target 对象的另一个方法)不会导致实际的 transaction 在运行时,即使调用的方法标记为@Transactional.也 代理必须完全初始化才能提供预期行为,因此您不应 在初始化代码中依赖此功能 — 例如,在@PostConstruct方法。

考虑使用 AspectJ 模式(参见mode属性),如果您 期望 self-invocations 也将与 transactions 一起包装。在这种情况下,有 首先没有代理。相反,目标类是 woven 的(即它的字节码 已修改)以支持@Transactional运行时行为。spring-doc.cadn.net.cn

表 1.注释驱动的事务设置
XML 属性 注释属性 违约 描述

transaction-managerspring-doc.cadn.net.cn

N/A(请参阅TransactionManagementConfigurerjavadoc)spring-doc.cadn.net.cn

transactionManagerspring-doc.cadn.net.cn

要使用的事务管理器的名称。仅当交易名称 manager 不是transactionManager,如前面的示例所示。spring-doc.cadn.net.cn

modespring-doc.cadn.net.cn

modespring-doc.cadn.net.cn

proxyspring-doc.cadn.net.cn

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

proxy-target-classspring-doc.cadn.net.cn

proxyTargetClassspring-doc.cadn.net.cn

falsespring-doc.cadn.net.cn

适用于proxy模式。控制创建的交易代理类型 对于用@Transactional注解。如果proxy-target-class属性设置为true,将创建基于类的代理。如果proxy-target-classfalse或者,如果省略该属性,则基于 JDK 接口的标准代理为 创建。(有关详细检查,请参见代理机制 的不同代理类型。spring-doc.cadn.net.cn

orderspring-doc.cadn.net.cn

orderspring-doc.cadn.net.cn

Ordered.LOWEST_PRECEDENCEspring-doc.cadn.net.cn

定义应用于 Comments 为@Transactional.(有关 AOP 排序相关规则的更多信息 建议,请参阅 建议排序。 没有指定的 Sequences 意味着 AOP 子系统确定通知的 Sequences。spring-doc.cadn.net.cn

用于处理的默认通知模式@Transactionalannotations 为proxy, ,它仅允许通过代理拦截调用。本地调用 同一个类不能以这种方式被拦截。对于更高级的拦截模式, 考虑切换到aspectj模式与编译时或加载时编织结合使用。
proxy-target-class属性 控制事务代理的类型 为使用@Transactional注解。如果proxy-target-class设置为true,将创建基于类的代理。如果proxy-target-classfalse或者,如果省略了该属性,则使用标准 JDK 创建基于接口的代理。(有关不同代理类型的讨论,请参阅 代理机制
@EnableTransactionManagement<tx:annotation-driven/>查找@Transactional仅在定义它们的同一应用程序上下文中的 bean 上。 这意味着,如果您将注解驱动的配置放在WebApplicationContext对于DispatcherServlet,它会检查@Transactional仅在控制器中的 bean 而不是在你的服务中。有关更多信息,请参阅 MVC

在评估事务设置时,派生程度最高的位置优先 对于方法。在以下示例中,DefaultFooServiceclass 为 在类级别使用只读事务的设置进行注释,但@Transactional注解updateFoo(Foo)method 采用 优先于在 Class 级别定义的事务设置。spring-doc.cadn.net.cn

@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(readOnly = true)
class DefaultFooService : FooService {

	override fun getFoo(fooName: String): Foo {
		// ...
	}

	// these settings have precedence for this method
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	override fun updateFoo(foo: Foo) {
		// ...
	}
}

@Transactional设置

@Transactionalannotation 是指定接口、类、 或方法必须具有事务语义(例如,“启动全新的只读 transaction 来暂停任何现有事务”)。 默认的@Transactional设置如下:spring-doc.cadn.net.cn

您可以更改这些默认设置。下表总结了各种 的属性@Transactional注解:spring-doc.cadn.net.cn

表 2.@Transactional设置
财产 类型 描述

spring-doc.cadn.net.cn

Stringspring-doc.cadn.net.cn

指定要使用的事务管理器的可选限定符。spring-doc.cadn.net.cn

transactionManagerspring-doc.cadn.net.cn

Stringspring-doc.cadn.net.cn

别名value.spring-doc.cadn.net.cn

labelspring-doc.cadn.net.cn

数组Stringlabels 向事务添加富有表现力的描述。spring-doc.cadn.net.cn

事务管理器可以评估标签,以将特定于实现的行为与实际事务相关联。spring-doc.cadn.net.cn

增殖spring-doc.cadn.net.cn

enum:Propagationspring-doc.cadn.net.cn

可选的传播设置。spring-doc.cadn.net.cn

isolationspring-doc.cadn.net.cn

enum:Isolationspring-doc.cadn.net.cn

可选隔离级别。仅适用于REQUIREDREQUIRES_NEW.spring-doc.cadn.net.cn

timeoutspring-doc.cadn.net.cn

int(以秒为单位)spring-doc.cadn.net.cn

可选的事务超时。仅适用于REQUIREDREQUIRES_NEW.spring-doc.cadn.net.cn

timeoutStringspring-doc.cadn.net.cn

String(以秒为单位)spring-doc.cadn.net.cn

用于指定timeout以秒为单位作为Stringvalue — 例如,作为占位符。spring-doc.cadn.net.cn

readOnlyspring-doc.cadn.net.cn

booleanspring-doc.cadn.net.cn

读写与只读事务。仅适用于REQUIREDREQUIRES_NEW.spring-doc.cadn.net.cn

rollbackForspring-doc.cadn.net.cn

数组Class对象,这些对象必须派生自Throwable.spring-doc.cadn.net.cn

必须导致回滚的异常类型的可选数组。spring-doc.cadn.net.cn

rollbackForClassNamespring-doc.cadn.net.cn

异常名称模式的数组。spring-doc.cadn.net.cn

必须导致回滚的异常名称模式的可选数组。spring-doc.cadn.net.cn

noRollbackForspring-doc.cadn.net.cn

数组Class对象,这些对象必须派生自Throwable.spring-doc.cadn.net.cn

不得导致回滚的异常类型的可选数组。spring-doc.cadn.net.cn

noRollbackForClassNamespring-doc.cadn.net.cn

异常名称模式的数组。spring-doc.cadn.net.cn

不得导致回滚的异常名称模式的可选数组。spring-doc.cadn.net.cn

有关回滚规则语义、模式和警告的更多详细信息,请参阅回滚规则 关于基于模式的回滚规则的可能意外匹配。

从 6.2 开始,您可以全局更改默认回滚行为 – 例如,通过@EnableTransactionManagement(rollbackOn=ALL_EXCEPTIONS),导致回滚 对于事务中引发的所有异常,包括任何已检查的异常。 对于进一步的自定义,AnnotationTransactionAttributeSource提供了一个addDefaultRollbackRule(RollbackRuleAttribute)method 来自定义默认规则。spring-doc.cadn.net.cn

请注意,特定于事务的回滚规则会覆盖默认行为,但 为未指定的异常保留所选的默认值。这种情况 Spring的@Transactional以及 JTA 的jakarta.transaction.Transactional注解。spring-doc.cadn.net.cn

除非您依赖于具有提交行为的 EJB 样式业务异常,否则它是 建议切换到ALL_EXCEPTIONS为了实现一致的回滚语义 如果出现(可能是意外的)检查异常。此外,这是可取的 为没有强制执行的基于 Kotlin 的应用程序进行切换 的已检查异常。spring-doc.cadn.net.cn

目前,您无法对事务的名称进行显式控制,其中 'name' 表示出现在事务监视器和日志记录输出中的事务名称。 对于声明性事务,事务名称始终是完全限定类 事务性建议类的名称 +.+ 方法名称。例如,如果handlePayment(..)方法BusinessService类启动了事务,则 交易的 name 将为com.example.BusinessService.handlePayment.spring-doc.cadn.net.cn

多个事务管理器@Transactional

大多数 Spring 应用程序只需要一个事务 Management 器,但可能有 您希望在单个事务管理器中有多个独立的事务管理器的情况 应用。您可以使用valuetransactionManager属性的@Transactional注解来选择性地指定TransactionManager以供使用。这可以是 bean 名称或 qualifier 值 事务管理器 Bean 中。例如,使用限定符表示法,您可以 将以下 Java 代码与以下事务管理器 Bean 声明组合在一起 在应用程序上下文中:spring-doc.cadn.net.cn

public class TransactionalService {

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

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

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

	@Transactional("order")
	fun setSomething(name: String) {
		// ...
	}

	@Transactional("account")
	fun doSomething() {
		// ...
	}

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

下面的清单显示了 bean 声明:spring-doc.cadn.net.cn

<tx:annotation-driven/>

	<bean id="transactionManager1" class="org.springframework.jdbc.support.JdbcTransactionManager">
		...
		<qualifier value="order"/>
	</bean>

	<bean id="transactionManager2" class="org.springframework.jdbc.support.JdbcTransactionManager">
		...
		<qualifier value="account"/>
	</bean>

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

在这种情况下,对TransactionalService在 separate 下运行 事务管理器,通过order,accountreactive-account限定 符。默认的<tx:annotation-driven>目标 Bean 名称、transactionManager, 如果没有特别限定的,则仍使用TransactionManagerBean 的 Bean 中找到。spring-doc.cadn.net.cn

如果同一类上的所有事务方法共享相同的限定符,则考虑 声明类型级org.springframework.beans.factory.annotation.Qualifierannotation 来代替。如果其值与 Specific Transaction Manager,该事务管理器将用于 交易定义中没有特定限定符@Transactional本身。spring-doc.cadn.net.cn

这样的类型级限定符可以在具体类上声明,应用于 transaction 定义。这实际上会覆盖 任何非限定基类方法的默认事务管理器选项。spring-doc.cadn.net.cn

最后但并非最不重要的一点是,这样的类型级 bean 限定符可以用于多种用途, 例如,如果值为 “order”,则它可以用于自动装配目的(标识 Order 存储库)以及事务管理器选择,只要 用于自动装配的目标 bean 以及关联的事务管理器 definitions 声明相同的限定符值。这样的限定符值只需要 在一组类型匹配的 bean 中是唯一的,而不必用作 ID。spring-doc.cadn.net.cn

自定义组合注释

如果您发现您重复使用相同的属性@Transactional在许多不同的方法上, Spring 的元注释支持允许您为特定用例定义自定义组合的注释。例如,考虑 以下注释定义:spring-doc.cadn.net.cn

@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 {
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@Transactional(transactionManager = "order", label = ["causal-consistency"])
annotation class OrderTx

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@Transactional(transactionManager = "account", label = ["retryable"])
annotation class AccountTx

前面的注释让我们编写上一节中的示例,如下所示:spring-doc.cadn.net.cn

public class TransactionalService {

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

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

	@OrderTx
	fun setSomething(name: String) {
		// ...
	}

	@AccountTx
	fun doSomething() {
		// ...
	}
}

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