事务传播行为

前面已经讲解过事务的使用,但在一些场景下事务的使用会更加复杂。例如我们在处理一个业务时,该业务有几个部分组成,在执行中几个部分都完成了,但有一部分因为特殊原因没能够执行成功。按照事务的说法,要么全部成功,要么全部失败,所以在接下来的处理逻辑上,会因为一部分的失败,导致大部分的数据进行回滚。

显然这样不合理,在系统中可能会造成锁表,使系统卡死。我们的实际做法是保留成功的数据,然后回滚失败的部分,当然失败的那部分会进行后续的处理。这样的处理方式其实就是传播行为,通俗来说就是执行到某段代码时,对已存在事务采用不同处理方式。现在,来看在代码中定义的传播行为,代码如下所示。

package org.springframework.transaction.annotation;

public enum Propagation {
   REQUIRED(0),
   SUPPORTS(1),
   MANDATORY(2),
   REQUIRES_NEW(3),
   NOT_SUPPORTED(4),
   NEVER(5),
   NESTED(6);

   private final int value;

   private Propagation(int value) {
      this.value = value;
   }

   public int value() {
      return this.value;
   }
}

在上面的代码中,可以看到主要有七种事务传播行为。为了方便直观地说明,我们先假设一个批量处理是当前的执行交易,里面分几个小部分逻辑在执行,这里简化为一个,如图7.7所示。

image 2024 03 31 21 49 32 885
Figure 1. 图7.7 事务示意图

我们先通过一段代码进行说明,方便理解上面描述的示意图,代码如下所示。

class ServiceA{
   public void methodA(){
      //按照事务的方式调用方法B
      ServiceB.methodB();
   }
}

class ServiceB{
   public void methodB(){
      //to do
   }
}

下面我们通过表格展示传播行为及说明,如表7.6所示。

image 2024 03 31 21 50 38 290
Figure 2. 表7.6 传播行为及说明

我们通过举例来加深对传播行为的理解,使用按照 A、B 来说明。假如传播行为是 REQUIRED,在使用 A 时,会调用 B。如果 A 已经开启了事务,在调用 B 时,B 将会运行在 A 的事务内部;如果 A 没有开启事务,将会给 B 分配一个事务。这样使用,在 A 或者 B 中只要出现异常,事务都会进行回滚,当然 B 也可能已经提交,但仍然会进行回滚。这也是默认的传播行为。

假设 A 的传播行为是 REQUIRED,B 的传播行为是 NEVER,那么在执行 B 时,就会抛出异常。