Using @Transactional

除了基于 XML 的事务配置声明式方法之外,你还可以使用基于注释的方法。在 Java 源代码中直接声明事务语义将声明与受影响的代码紧密地联系在一起。没有过度耦合的太大危险,因为打算以事务方式使用的代码几乎总是以这种方式部署的。

In addition to the XML-based declarative approach to transaction configuration, you can use an annotation-based approach. Declaring transaction semantics directly in the Java source code puts the declarations much closer to the affected code. There is not much danger of undue coupling, because code that is meant to be used transactionally is almost always deployed that way anyway.

标准 jakarta.transaction.Transactional 注释也受支持,作为 Spring 自身注释的直接替换。有关更多详细信息,请参阅 JTA 文档。

The standard jakarta.transaction.Transactional annotation is also supported as a drop-in replacement to Spring’s own annotation. Please refer to the JTA documentation for more details.

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

The ease-of-use afforded by the use of the @Transactional annotation is best illustrated with an example, which is explained in the text that follows. Consider the following class definition:

  • Java

  • Kotlin

// 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) {
		// ...
	}
}

在类级别如上使用时,注解表示声明类(以及其子类)的所有方法的默认值。或者,可以单独对每个方法进行注解。请参阅 method visibility 以了解 Spring 认为是事务性方法的更多详细信息。请注意,类级注解不适用于类层次结构上方的祖先类;在这种情况下,需要在本地重新声明继承的方法,以便参与子类级别的注解。

Used at the class level as above, the annotation indicates a default for all methods of the declaring class (as well as its subclasses). Alternatively, each method can be annotated individually. See method visibility for further details on which methods Spring considers transactional. Note that a class-level annotation does not apply to ancestor classes up the class hierarchy; in such a scenario, inherited methods need to be locally redeclared in order to participate in a subclass-level annotation.

当像上面那样的 POJO 类在 Spring 上下文中被定义为 Bean 时,您可以通过 @Configuration 类中的 @EnableTransactionManagement 注解使 Bean 实例成为事务性的。请参阅https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/EnableTransactionManagement.html[javadoc] 以了解全部详细信息。

When a POJO class such as the one above is defined as a bean in a Spring context, you can make the bean instance transactional through an @EnableTransactionManagement annotation in a @Configuration class. See the javadoc for full details.

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

In XML configuration, the <tx:annotation-driven/> tag provides similar convenience:

<!-- 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 The line that makes the bean instance transactional.

如果要连接的 TransactionManager 的 Bean 名称具有名称 transactionManager,则可以在 <tx:annotation-driven/> 标记中省略 transaction-manager 属性。如果要依赖注入的 TransactionManager Bean 有任何其他名称,则必须使用 transaction-manager 属性,如前面的示例所示。

You can omit the transaction-manager attribute in the <tx:annotation-driven/> tag if the bean name of the TransactionManager that you want to wire in has the name transactionManager. If the TransactionManager bean that you want to dependency-inject has any other name, you have to use the transaction-manager attribute, as in the preceding example.

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

Reactive transactional methods use reactive return types in contrast to imperative programming arrangements as the following listing shows:

  • Java

  • Kotlin

// 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 有特殊考虑。有关更多详细信息,请参阅“使用事务操作符”下的 Cancel Signals 一节。

Note that there are special considerations for the returned Publisher with regards to Reactive Streams cancellation signals. See the Cancel Signals section under "Using the TransactionalOperator" for more details.

Method visibility and @Transactional in proxy mode

@Transactional 注解通常用于具有 public 可见性的方法。从 6.0 开始,默认情况下,protected 或者包可见的方法也可以对类级代理进行事务操作。请注意,基于接口的代理中的事务方法必须始终为 public,并且在代理接口中定义。对于这两种代理,只拦截通过代理传入的外部方法调用。

The @Transactional annotation is typically used on methods with public visibility. As of 6.0, protected or package-visible methods can also be made transactional for class-based proxies by default. Note that transactional methods in interface-based proxies must always be public and defined in the proxied interface. For both kinds of proxies, only external method calls coming in through the proxy are intercepted.

如果希望对不同种类的代理一致地处理方法可见性(这是 5.3 之前默认的做法),请考虑指定 publicMethodsOnly

If you prefer consistent treatment of method visibility across the different kinds of proxies (which was the default up until 5.3), consider specifying publicMethodsOnly:

/**
 * 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 Framework 默认情况下也支持非私有的 @Transactional 测试方法。有关示例,请参阅测试章节中的 Transaction Management

The Spring TestContext Framework supports non-private @Transactional test methods by default as well. See Transaction Management in the testing chapter for examples.

您可以将 @Transactional 注解应用于接口定义、接口上的方法、类定义或类上的方法。但是,只有 @Transactional 注解本身还不足以激活事务行为。@Transactional 注解只是一种元数据,相应的运行时基础结构可以使用这些元数据,并使用该元数据配置具有事务行为的适当 bean。在前面的示例中,<tx:annotation-driven/> 元素会在运行时开启实际的事务管理。

You can apply the @Transactional annotation to an interface definition, a method on an interface, a class definition, or a method on a class. However, the mere presence of the @Transactional annotation is not enough to activate the transactional behavior. The @Transactional annotation is merely metadata that can be consumed by corresponding runtime infrastructure which uses that metadata to configure the appropriate beans with transactional behavior. In the preceding example, the <tx:annotation-driven/> element switches on actual transaction management at runtime.

Spring 团队建议使用 @Transactional 注释对具体类的メソッド进行注释,而不是依赖于接口中的注释方法,即使后者对基于接口和目标类的代理在 5.0 中有效也是如此。由于 Java 注释不会从接口继承,因此在使用 AspectJ 模式时,界面声明的注释仍然不会被织入基础结构识别,因此不会应用该方面。结果,你的事务注释可能会被忽略:在测试回滚方案之前,你的代码可能会“正常”工作。

The Spring team recommends that you annotate methods of concrete classes with the @Transactional annotation, rather than relying on annotated methods in interfaces, even if the latter does work for interface-based and target-class proxies as of 5.0. Since Java annotations are not inherited from interfaces, interface-declared annotations are still not recognized by the weaving infrastructure when using AspectJ mode, so the aspect does not get applied. As a consequence, your transaction annotations may be silently ignored: Your code might appear to "work" until you test a rollback scenario.

在代理模式(它是默认模式)中,仅拦截通过代理传入的外部方法调用。这意味着自调用(实际上,目标对象中的方法调用目标对象中的另一个方法)不会导致实际事务在运行时,即使调用的方法用 @Transactional 标记。此外,必须完全初始化代理以提供预期的行为,因此你不应在此功能中依赖初始化代码 — 例如在 @PostConstruct 方法中。

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code — e.g. in a @PostConstruct method.

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

Consider using AspectJ mode (see the mode attribute in the following table) if you expect self-invocations to be wrapped with transactions as well. In this case, there is no proxy in the first place. Instead, the target class is woven (that is, its byte code is modified) to support @Transactional runtime behavior on any kind of method.

Table 1. Annotation driven transaction settings
XML Attribute Annotation Attribute Default Description

transaction-manager

N/A (see TransactionManagementConfigurer javadoc)

transactionManager

Name of the transaction manager to use. Required only if the name of the transaction manager is not transactionManager, as in the preceding example.

mode

mode

proxy

The default mode (proxy) processes annotated beans to be proxied by using Spring’s AOP framework (following proxy semantics, as discussed earlier, applying to method calls coming in through the proxy only). The alternative mode (aspectj) instead weaves the affected classes with Spring’s AspectJ transaction aspect, modifying the target class byte code to apply to any kind of method call. AspectJ weaving requires spring-aspects.jar in the classpath as well as having load-time weaving (or compile-time weaving) enabled. (See Spring configuration for details on how to set up load-time weaving.)

proxy-target-class

proxyTargetClass

false

Applies to proxy mode only. Controls what type of transactional proxies are created for classes annotated with the @Transactional annotation. If the proxy-target-class attribute is set to true, class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, then standard JDK interface-based proxies are created. (See Proxying Mechanisms for a detailed examination of the different proxy types.)

order

order

Ordered.LOWEST_PRECEDENCE

Defines the order of the transaction advice that is applied to beans annotated with @Transactional. (For more information about the rules related to ordering of AOP advice, see Advice Ordering.) No specified ordering means that the AOP subsystem determines the order of the advice.

处理 @Transactional 注释的默认建议模式为 proxy,它只允许拦截通过代理的调用。同类中的本地调用无法以这种方式被拦截。对于更高级的拦截模式,请考虑与编译时或加载时编织结合切换到 aspectj 模式。

The default advice mode for processing @Transactional annotations is proxy, which allows for interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way. For a more advanced mode of interception, consider switching to aspectj mode in combination with compile-time or load-time weaving.

proxy-target-class 属性控制为使用 @Transactional 注释注释的类创建哪类事务代理。如果将 proxy-target-class 设置为 true,则创建基于类的代理。如果 proxy-target-classfalse 或省略属性,则创建标准基于 JDK 接口的代理。(参阅 Proxying Mechanisms 了解不同代理类型的讨论。)

The proxy-target-class attribute controls what type of transactional proxies are created for classes annotated with the @Transactional annotation. If proxy-target-class is set to true, class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, standard JDK interface-based proxies are created. (See Proxying Mechanisms for a discussion of the different proxy types.)

@EnableTransactionManagement<tx:annotation-driven/> 仅在与其定义在同一应用程序上下文中的 Bean 上查找 @Transactional。这意味着,如果您为 DispatcherServletWebApplicationContext 中放置了由注释驱动的配置,它只在您的控制器中检查 @Transactional Bean,而不在您的服务中检查。请参阅 MVC 了解更多信息。

@EnableTransactionManagement and <tx:annotation-driven/> look for @Transactional only on beans in the same application context in which they are defined. This means that, if you put annotation-driven configuration in a WebApplicationContext for a DispatcherServlet, it checks for @Transactional beans only in your controllers and not in your services. See MVC for more information.

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

The most derived location takes precedence when evaluating the transactional settings for a method. In the case of the following example, the DefaultFooService class is annotated at the class level with the settings for a read-only transaction, but the @Transactional annotation on the updateFoo(Foo) method in the same class takes precedence over the transactional settings defined at the class level.

  • Java

  • Kotlin

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

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

The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics (for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction"). The default @Transactional settings are as follows:

  • The propagation setting is PROPAGATION_REQUIRED.

  • The isolation level is ISOLATION_DEFAULT.

  • The transaction is read-write.

  • The transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.

  • Any RuntimeException or Error triggers rollback, and any checked Exception does not.

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

You can change these default settings. The following table summarizes the various properties of the @Transactional annotation:

Table 2. @Transactional Settings
Property Type Description

value

String

Optional qualifier that specifies the transaction manager to be used.

transactionManager

String

Alias for value.

label

Array of String labels to add an expressive description to the transaction.

Labels may be evaluated by transaction managers to associate implementation-specific behavior with the actual transaction.

propagation

enum: Propagation

Optional propagation setting.

isolation

enum: Isolation

Optional isolation level. Applies only to propagation values of REQUIRED or REQUIRES_NEW.

timeout

int (in seconds of granularity)

Optional transaction timeout. Applies only to propagation values of REQUIRED or REQUIRES_NEW.

timeoutString

String (in seconds of granularity)

Alternative for specifying the timeout in seconds as a String value — for example, as a placeholder.

readOnly

boolean

Read-write versus read-only transaction. Only applicable to values of REQUIRED or REQUIRES_NEW.

rollbackFor

Array of Class objects, which must be derived from Throwable.

Optional array of exception types that must cause rollback.

rollbackForClassName

Array of exception name patterns.

Optional array of exception name patterns that must cause rollback.

noRollbackFor

Array of Class objects, which must be derived from Throwable.

Optional array of exception types that must not cause rollback.

noRollbackForClassName

Array of exception name patterns.

Optional array of exception name patterns that must not cause rollback.

请参阅 Rollback rules 以进一步了解回滚规则语义、模式以及有关基于模式的回滚规则可能无意间匹配的警告。

See Rollback rules for further details on rollback rule semantics, patterns, and warnings regarding possible unintentional matches for pattern-based rollback rules.

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

As of 6.2, you can globally change the default rollback behavior – for example, through @EnableTransactionManagement(rollbackOn=ALL_EXCEPTIONS), leading to a rollback for all exceptions raised within a transaction, including any checked exception. For further customizations, AnnotationTransactionAttributeSource provides an addDefaultRollbackRule(RollbackRuleAttribute) method for custom default rules.

请注意,特定于事务的回滚规则会覆盖默认行为,但会保留对未指定异常所选的默认行为。这适用于 Spring 的 @Transactional 以及 JTA 的 jakarta.transaction.Transactional 注解。

Note that transaction-specific rollback rules override the default behavior but retain the chosen default for unspecified exceptions. This is the case for Spring’s @Transactional as well as JTA’s jakarta.transaction.Transactional annotation.

除非依赖具有提交行为的 EJB 风格业务异常,否则建议即使在(潜在意外)经检查异常的情况下,也切换到 ALL_EXCEPTIONS 以获得一致的回滚语义。此外,建议在基于 Kotlin 的应用程序中进行此切换,因为根本不强制执行经检查异常。

Unless you rely on EJB-style business exceptions with commit behavior, it is advisable to switch to ALL_EXCEPTIONS for consistent rollback semantics even in case of a (potentially accidental) checked exception. Also, it is advisable to make that switch for Kotlin-based applications where there is no enforcement of checked exceptions at all.

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

Currently, you cannot have explicit control over the name of a transaction, where 'name' means the transaction name that appears in a transaction monitor and in logging output. For declarative transactions, the transaction name is always the fully-qualified class name of the transactionally advised class + . + the method name. For example, if the handlePayment(..) method of the BusinessService class started a transaction, the name of the transaction would be com.example.BusinessService.handlePayment.

Multiple Transaction Managers with @Transactional

大多数 Spring 应用程序只需一个事务管理器,但在某些情况下,您可能希望在一个应用程序中有多个独立的事务管理器。您可以使用 @Transactional 注解的 valuetransactionManager 属性来选择性地指定要使用的 TransactionManager 的标识。这可以是交易管理器 bean 的 bean 名称或限定符值。例如,使用限定符表示法时,可以将以下 Java 代码与应用程序上下文中以下事务管理器 bean 声明结合使用:

Most Spring applications need only a single transaction manager, but there may be situations where you want multiple independent transaction managers in a single application. You can use the value or transactionManager attribute of the @Transactional annotation to optionally specify the identity of the TransactionManager to be used. This can either be the bean name or the qualifier value of the transaction manager bean. For example, using the qualifier notation, you can combine the following Java code with the following transaction manager bean declarations in the application context:

  • Java

  • Kotlin

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 声明:

The following listing shows the bean declarations:

<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 上的各个方法在不同的事务管理器下运行,这些事务管理器通过 orderaccountreactive-account 限定符进行区分。默认 <tx:annotation-driven> 目标 bean 名称 transactionManager 仍用于未找到特定限定符的 TransactionManager bean 的情况。

In this case, the individual methods on TransactionalService run under separate transaction managers, differentiated by the order, account, and reactive-account qualifiers. The default <tx:annotation-driven> target bean name, transactionManager, is still used if no specifically qualified TransactionManager bean is found.

如果同一类上的所有事务方法共享相同的限定符,请考虑声明一个类型级别的 org.springframework.beans.factory.annotation.Qualifier 注解。如果它的值与特定事务管理器的限定符值(或 bean 名称)匹配,则该事务管理器将用于没有在 @Transactional 本身上指定特定限定符的事务定义。

If all transactional methods on the same class share the same qualifier, consider declaring a type-level org.springframework.beans.factory.annotation.Qualifier annotation instead. If its value matches the qualifier value (or bean name) of a specific transaction manager, that transaction manager is going to be used for transaction definitions without a specific qualifier on @Transactional itself.

此类类型级别限定符可以在具体类上声明,也可以应用于基类中的事务定义。这实际上覆盖了任何不合格基类方法的默认事务管理器选择。

Such a type-level qualifier can be declared on the concrete class, applying to transaction definitions from a base class as well. This effectively overrides the default transaction manager choice for any unqualified base class methods.

最后但并非最不重要的是,这样的类型级bean限定符可以起到多种用途,例如:当值为“order”时,可以用它进行自动注入(识别order存储库)以及事务管理器选择,只要用于自动注入的目标bean以及关联的事务管理器定义都声明了相同的限定符值即可。这样的限定符值只需在匹配类型的bean集合中才是唯一的,而不必用作ID。

Last but not least, such a type-level bean qualifier can serve multiple purposes, e.g. with a value of "order" it can be used for autowiring purposes (identifying the order repository) as well as transaction manager selection, as long as the target beans for autowiring as well as the associated transaction manager definitions declare the same qualifier value. Such a qualifier value only needs to be unique within a set of type-matching beans, not having to serve as an ID.

Custom Composed Annotations

如果你发现自己在许多不同的方法上重复使用相同的属性, Spring’s meta-annotation support 让你可以定义自定义组合注解以满足你的特定用例。例如,考虑以下注解定义:

If you find you repeatedly use the same attributes with @Transactional on many different methods, Spring’s meta-annotation support lets you define custom composed annotations for your specific use cases. For example, consider the following annotation definitions:

  • Java

  • Kotlin

@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

前面的注释让我们可以将上一节中的示例编写成如下内容:

The preceding annotations let us write the example from the previous section as follows:

  • Java

  • Kotlin

public class TransactionalService {

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

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

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

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

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

In the preceding example, we used the syntax to define the transaction manager qualifier and transactional labels, but we could also have included propagation behavior, rollback rules, timeouts, and other features.