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

@Transactional

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

标准jakarta.transaction.Transactional注释也支持 Spring 自己的注释的直接替换。请参阅 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) {
		// ...
	}
}

如上所述,在类级别使用,注释指示所有方法的默认值 声明类(及其子类)的。或者,每种方法都可以是 单独注释。有关 Spring 认为哪些方法是事务性的更多详细信息,请参阅方法可见性。请注意,类级 注释不适用于类层次结构上的祖先类;在这种情况下, 继承的方法需要在本地重新声明才能参与 子类级注释。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/>标记,如果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关于 响应式流取消信号。有关更多详细信息,请参阅“使用 TransactionalOperator”下的 Cancel Signals 部分。spring-doc.cadn.net.cn

方法可见性和@Transactional在代理模式下

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

如果您更喜欢在不同类型的 代理(在 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测试方法 默认情况下也是如此。有关示例,请参阅测试章节中的事务管理spring-doc.cadn.net.cn

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

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

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

表 1.注释驱动的事务设置
XML 属性 注释属性 默认值 描述

transaction-managerspring-doc.cadn.net.cn

不适用(参见TransactionManagementConfigurerjavadoc)spring-doc.cadn.net.cn

transactionManagerspring-doc.cadn.net.cn

要使用的事务管理器的名称。仅当事务名称 经理不是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

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

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

在评估事务设置时,派生最多的位置优先 对于一种方法。在以下示例中,DefaultFooServiceclass 是 在类级别使用只读事务的设置进行注释,但@Transactional注释updateFoo(Foo)method 接受同一类中的 优先于在类级别定义的事务设置。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设置

@Transactional注释是元数据,指定接口、类、 或方法必须具有事务语义(例如,“启动全新的只读 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

数组String标签,为交易添加富有表现力的描述。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)自定义默认规则的方法。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类启动事务,则 事务名称将为com.example.BusinessService.handlePayment.spring-doc.cadn.net.cn

多个事务管理器@Transactional

大多数 Spring 应用程序只需要一个事务管理器,但可能有 您希望在单个事务管理器中包含多个独立事务管理器的情况 应用。您可以使用valuetransactionManager属性的@Transactional注释来选择指定TransactionManager待使用。这可以是 bean 名称或限定符值 事务管理器 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在单独的 事务管理器,由order,accountreactive-account限定 符。默认值<tx:annotation-driven>目标 bean 名称,transactionManager, 如果没有特别限定的,则仍使用TransactionManager豆子被找到。spring-doc.cadn.net.cn

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

可以在具体类上声明这样的类型级限定符,应用于 事务定义也来自基类。这有效地覆盖了 任何不限定的基类方法的默认事务管理器选项。spring-doc.cadn.net.cn

最后但并非最不重要的一点是,这样的类型级 bean 限定符可以用于多种用途, 例如,值为“order”时,它可用于自动布线目的(识别 订单存储库)以及事务管理器选择,只要 用于自动装配的目标 Bean 以及关联的事务管理器 定义声明相同的限定符值。这样的限定符值只需要 在一组类型匹配的 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