SpringDataSourceAndTransaction使用指导

总结摘要
Spring 数据源与事务使用介绍

前言

Spring 中注解驱动的事务使用方法。

  1. 启用注解驱动。
    1. SpringBoot 自动配置声明注解@EnableTransactionManagement
    2. 用户主动声明注解@EnableTransactionManagement
  2. 在期望使用事务的类或方法上声明注解@Transactional
    1. 该注解中支持配置事务相关属性,包括事务传播模式,事务管理器,回滚配置,隔离级别等。

注解-EnableTransactionManagement

启用 Spring 的注解驱动事务管理功能。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// org.springframework.transaction.annotation.EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

	// 指示是否要创建基于子类的(CGLIB)代理(`true`),而不是基于标准 Java 接口的代理(`false`)。
    // 默认值为 `false`。仅在 `mode()` 设置为 `AdviceMode.PROXY` 时适用。
    // 请注意,将此属性设置为 `true` 将影响所有需要代理的 Spring 管理的 Bean,而不仅仅是那些标记为 `@Transactional` 的 Bean。
    // 例如,标记为 Spring 的 `@Async` 注解的其他 Bean 也会同时升级为子类代理。在实践中,这种方法通常不会产生负面影响,除非明确期望一种类型的代理而不是另一种,例如在测试中。
	boolean proxyTargetClass() default false;

	// 指示事务通知应该如何应用。
    // 默认值是 `AdviceMode.PROXY`。
    // 请注意,代理模式仅允许拦截通过代理进行的调用。同一类内的本地调用无法以这种方式被拦截;在本地调用中,`@Transactional` 注解的方法将被忽略,因为 Spring 的拦截器在这种运行时场景中甚至不会启动。
    // 对于更高级的拦截模式,可以考虑将其切换为 `AdviceMode.ASPECTJ`。
	AdviceMode mode() default AdviceMode.PROXY;

	// 指示当多个通知应用于特定连接点时,事务通知器的执行顺序。
    // 默认值为 Ordered.LOWEST_PRECEDENCE。
	int order() default Ordered.LOWEST_PRECEDENCE;

}    

注解-Transactional

注解Transactional描述了一个事务属性,可以应用于单个方法或类。

当此注解在类级别声明时,它将作为默认值应用于声明类及其子类的所有方法。请注意,它不会应用于类层次结构中的祖先类;继承的方法需要在本地重新声明,才能参与子类级别的注解。

如果此注解中未配置自定义回滚规则,则事务将在抛出 RuntimeException 和 Error 时回滚,但不会在抛出受检查的异常时回滚。

可以通过 rollbackFor/noRollbackFor 和 rollbackForClassName/noRollbackForClassName 配置回滚规则,它们分别允许以类引用或字符串的形式指定模式。当以类引用的形式指定异常类型时,将使用其完全限定名作为模式。因此,@Transactional(rollbackFor = example.CustomException.class)等同于 @Transactional(rollbackForClassName = "example.CustomException")

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// org.springframework.transaction.annotation.Transactional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    // 参见 transactionManager
	@AliasFor("transactionManager")
	String value() default "";

    // 指定事务的限定符值。
    // 可用于确定目标事务管理器,匹配特定事务管理器 Bean 定义的限定符值(或 Bean 名称)。
	@AliasFor("value")
	String transactionManager() default "";

    // 定义零个或多个事务标签。
    // 标签可用于描述事务,并且可以由各个事务管理器进行评估。标签可能仅用于描述目的,也可以映射到预定义的事务管理器特定选项。
	String[] label() default {};

    // 事务传播类型。
    // 默认值为 Propagation.REQUIRED。
	Propagation propagation() default Propagation.REQUIRED;

    // 事务隔离级别。
    // 默认值为 Isolation.DEFAULT。
    // 仅适用于 Propagation.REQUIRED 或 Propagation.REQUIRES_NEW,因为它仅适用于新启动的事务。
    // 如果您希望在参与具有不同隔离级别的现有事务时拒绝隔离级别声明,请考虑将事务管理器的 "validateExistingTransactions" 标志设置为 "true"。
	Isolation isolation() default Isolation.DEFAULT;

    // 此事务的超时时间(以秒为单位)。
    // 默认值为底层事务系统的默认超时时间。
    // 仅适用于 Propagation.REQUIRED 或 Propagation.REQUIRES_NEW,因为它仅适用于新启动的事务。
    // 禁止`timeout`与`timeoutString`同时配置。
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

    // 此事务的超时时间(以秒为单位)。
    // 默认值为底层事务系统的默认超时时间。
    // 仅适用于 Propagation.REQUIRED 或 Propagation.REQUIRES_NEW,因为它仅适用于新启动的事务。
    // 禁止`timeout`与`timeoutString`同时配置。
	String timeoutString() default "";

    // 一个布尔标志,如果事务实际上是只读的,可以将其设置为 true,从而在运行时允许进行相应的优化。
    // 默认值为 false。
    // 这只是一个对实际事务子系统的提示;它不会必然导致写入访问尝试失败。无法解释只读提示的事务管理器在被要求提供只读事务时不会抛出异常,而是会默默地忽略该提示。
	boolean readOnly() default false;

    // 配置回滚规则
	Class<? extends Throwable>[] rollbackFor() default {};

    // 配置回滚规则
	String[] rollbackForClassName() default {};

    // 配置回滚规则
	Class<? extends Throwable>[] noRollbackFor() default {};

    // 配置回滚规则
	String[] noRollbackForClassName() default {};

}

属性解析逻辑

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)

传播行为

Spring通过Propagation枚举类定义了7种传播行为。

传播行为说明解释
REQUIREDSupport a current transaction, create a new one if none exists. Analogous to EJB transaction attribute of the same name. This is the default setting of a transaction annotation.如果当前没有事务,就新建一个事务;如果当前存在事务,就加入到这个事务中。 这是默认的事务传播行为。
SUPPROTSSupport a current transaction, execute non-transactionally if none exists. Analogous to EJB transaction attribute of the same name. Note: For transaction managers with transaction synchronization, SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope. Note that this depends on the actual synchronization configuration of the transaction manager.如果当前没有事务,就以非事务方式执行;如果当前存在事务,就加入到这个事务中。
MANADATORYSupport a current transaction, throw an exception if none exists. Analogous to EJB transaction attribute of the same name.如果当前没有事务,就抛出异常;如果当前存在事务,就加入到这个事务中。
REQUIRES_NEWCreate a new transaction, and suspend the current transaction if one exists. Analogous to the EJB transaction attribute of the same name. NOTE: Actual transaction suspension will not work out-of-the-box on all transaction managers. This in particular applies to org.springframework.transaction.jta.JtaTransactionManager
, which requires the jakarta.transaction.TransactionManager
to be made available to it (which is server-specific in standard Jakarta EE).
如果当前没有事务,就新建一个事务;如果当前存在事务,就挂起当前事务并新建一个事务。
NOT_SUPPORTEDExecute non-transactionally, suspend the current transaction if one exists. Analogous to EJB transaction attribute of the same name. NOTE: Actual transaction suspension will not work out-of-the-box on all transaction managers. This in particular applies to org.springframework.transaction.jta.JtaTransactionManager
, which requires the jakarta.transaction.TransactionManager
to be made available to it (which is server-specific in standard Jakarta EE).
以非事务方式执行;如果当前存在事务,就挂起当前事务。
NEVERExecute non-transactionally, throw an exception if a transaction exists. Analogous to EJB transaction attribute of the same name.以非事务方式执行;如果当前存在事务,就抛出异常。
NESTEDExecute within a nested transaction if a current transaction exists, behave like REQUIRED otherwise. There is no analogous feature in EJB. Note: Actual creation of a nested transaction will only work on specific transaction managers. Out of the box, this only applies to the JDBC DataSourceTransactionManager. Some JTA providers might support nested transactions as well.如果当前没有事务,就新建一个事务(类似于REQUIRED
);如果当前存在事务,则作为当前事务的子事务执行。

END