lun先生

导航

Spring事务的传播行为

Spring事务的传播行为

1. 概述

当我们遇到下面的情况时,一个service中调用了另一个service中的方法(两个service中都存在事务),此时bservice中的事务就被传播到了aservice中,这样就产生了事务的传播。

@Sercice
public class Aservice{
    @AutoWired
    private Bservice bservice;
    public void order(){
        yyyy();
        bservice.xxxx();
        zzzz();
    }
}

因为两个service都存在事务,那么生成的sql语句可能如下

BEGIN 
    update yyyy;
    -------两个事务的分割线------
        BEGIN 
          updata xxxx;
        COMMIT;
    ---------------------------
    update zzzz;
COMMIT;  

很显然,上面的mysql语句是不支持的。

那么这里就存在一个问题,在mysql中,当第二个begin执行时,会隐式的将第一个事务直接提交了,从而导致aservice中的zzzz()方法最终会以一个无事务的状态去运行。

所以,当【B事务】传播到【A事务中】时,【B事务】要做一下微调,而微调的结果可以分为以下几种情况。

(1)当Aservice中有事务

1. 融入事务

第一种情况,Bservice中的事务融入Aservice中的事务(融入A事务),这种场景是最多的

BEGIN 
    update yyyy;
    -------两个事务的分割线------
          updata xxxx; # B事务融入到A事务中
    ---------------------------
    update zzzz;
COMMIT;  

2. 挂起事务

第二种情况,挂起【A事务】,让【B事务】独立于【A事务】去运行。
当两个事务需要各自独立维护自身事务, 单个事务则无法独立完成,【B事务】启动时可以先给【A事务】暂时挂起,就是阻塞住不给【A事务】继续发送sql,从而让【A事务】无法去提交,B开启一个新的事务,B执行完成后,【A事务】继续。

(1)当Aservice中无事务

1. 以事务的方式运行

第一种情况: 【B事务】以事务的方式运行

select yyyy;
   -------两个事务的分割线------
    BEGIN 
      updata xxxx;
    COMMIT;
   ---------------------------
select zzzz;  

2. 以无事务的方式运行

第一种情况: 【B事务】以无事务的方式运行

select yyyy;
   -------两个事务的分割线------
    select xxxx;
   ---------------------------
select zzzz;  

3. 嵌套事务

BEGIN 
    update yyyy;
    --两个事务的分割线(模拟伪事务)--
    SAVEPOINT a; 
          updata xxxx;
    ROLLBACK TO a;
    ---------------------------
    update zzzz;
COMMIT;  

嵌套过程如下:

  1. 内部SAVEPOINT a的代码如果有问题,则直接回滚至保存点。
  2. 整个事务的提交也不受内部事务(伪事务)的影响。

2. 传播事务

@Transactional(propagation = 下面的值)

  • Propagation.REQUIRED:表示当前方法必须运行在事务中,如果外界有事务存在,方法就会在外界事务中运行,否则,就会启动一个新的事务。REQUIRED就是需要,意思就是B无论如何要有事务。
  • Propagation.SUPPORTS: 表示当前方法不需要事务上下文,如果外界存在事务的话,那么该方法就在外界的事务中运行,否则执行该方法时也不需要事务。
  • Propagation.MANDATORY: (强制性的),表示该方法必须在事务中运行,如果外界事务不存在,就会抛出一个IllegalTransactionStateException异常。
  • Propagation.REQUIRES_NEW: (需要个新的),表示当前方法必须运行在自己的事务中,一个新的事务将被启动,如果外部事务存在,在该方法运行期间,外部事务将会被挂起。
  • Propagation.NOT_SUPPORTED: (不支持事务),表示当前方法不应该运行在事务中,如果存在外部事务,那么在该方法运行期间,会将外部事务挂起,独立的去以非事务的方式去运行当前方法,当前方法运行结束后,再唤醒外部事务。
  • Propagation.NEVER: (不运行在有事务的环境中), 表示当前方法不应该运行在事务的上下文当中,如果该方法外部存在事务,就会抛出IllegalTransactionStateException异常。
  • Propagation.NESTED:(嵌套的) 表示如果存在外部事务,那么该方法将会在外部事务嵌套自己的事务去运行。嵌套的事务可以独立于外部事务进行单独的提交或者回滚,如果外部事务不存在,那么当前方法会自己创造一个事务,在自己创造的事务中运行。

注意: 不同的数据库语言对这种嵌套事务的支持是有所差异的。有的支持,有的不支持。

posted on 2024-01-31 14:52  lun先生  阅读(15)  评论(0)    收藏  举报