图解spring中七种事务传播行为 终于有人讲明白了

Posted java叶新东老师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图解spring中七种事务传播行为 终于有人讲明白了相关的知识,希望对你有一定的参考价值。

 

什么是传播行为?

  默认情况下,只有一个事务,所有的修改操作都在一个事务里面,要么一起提交,要么一起回滚,这没什么问题。但要是有2个或者2个事务以上该如何解决呢?

  既然是传播,那么至少要有2个东西,才可以传播,我传给你或者你传给我,才叫传播,单体不存在传播这个行为;

  事务传播行为,指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。比如说,A事务方法调用了B事务方法,B是继续在调用者A的事务中运行呢?还是为自己另开一个新事物运行? 这就是由B的事务传播行为决定的。

spring事务传播行为一共有7种:(前言: 当前事务指的是调用者自带的事务,A调用B,那么A就是当前事务)

  1. REQUIRED  (默认传播行为),支持当前事务,如果当前没有事务,就新建一个事务,这个当前事务指的是上一个方法的事务,是别人传递过去的,类似于重入锁,A方法和B方法都有事务,A方法调用B方法,A的事务会传递给B,使它们共用同一个事务,我起了个名字叫做重入事务
  2. SUPPORTS 如果存在一个事务,支持当前事务,如果没有事务,则非事务执行,
  3. REQUIRES_NEW  开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起
  4. MANDATORY  如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常 
  5. NOT_SUPPORTED  总是非事务地执行,并挂起任何存在的事务
  6. NEVER   总是非事务地执行,不加入任何事务;
  7. NESTED   如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按  REQUIRED 属性执行。 

 

大体讲完了, 接下来, 我们一个个地细化讲解,为了方便大家理解,下面的例子会把里面的AB方法以及其他概念做一些转化;具体关系如下:

A ---------------->  哥哥
B ----------------> 
执行代码 ------> 读书
事务------------->  吃苹果
挂起事务 ------>  暂停吃苹果
抛异常 ----- --->  妈妈发脾气

1、REQUIRED  

支持当前事务,如果当前没有事务,就新建一个事务。很好理解,不管有几个事务存在,都合并成一个事务来处理,只要有一个事务抛出异常,所有事务都会回滚;

大白话:哥哥和我,我们两个人每人都有一个苹果,最终我们的苹果会合并成一个苹果一起吃;

举例代码

  // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertB(){
        // do something
    }

2、SUPPORTS 

如果存在一个事务,支持当前事务,如果没有事务,则非事务执行。

大白话:如果哥哥有一个苹果,我就吃哥哥的苹果,如果哥哥没有苹果,那我也没得吃;

使用举例

   // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.SUPPORTS)
    public void insertB(){
        // do something
    }

 

3、REQUIRES_NEW  

开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起,

大白话:不管怎样,我都会得到一个新的苹果,如果哥哥正在吃苹果,那么他吃苹果的动作会先暂停,等我吃完之后哥哥在继续吃;

使用举例

  // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertB(){
        // do something
    }

4、MANDATORY 

如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常 

大白话:如果哥哥有一个苹果,那么我也吃他的苹果,如果哥哥没有苹果,妈妈就会发脾气;

使用举例--第一种情况,没有当前事务,controller 直接调用方法B

   // 方法B
    @Transactional(propagation = Propagation.MANDATORY)
    public void insertB(){
        // do something
    }

第二种情况,有当前事务

 // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.MANDATORY)
    public void insertB(){
        // do something
    }

5、NOT_SUPPORTED  

总是非事务地执行,并挂起任何存在的事务

大白话:我总是不吃苹果,如果哥哥正在吃苹果,遇到我正在读书,哥哥会暂停吃苹果这个行为,待我读书读完后,哥哥就会继续吃苹果

代码举例

 // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void insertB(){
        // do something
    }

6、NEVER 

总是非事务地执行,不加入任何事务;如果存在一个活动事务,则抛出异常。

大白话:我总是不吃苹果,如果哥哥有苹果,那妈妈就会发脾气

代码举例,第一种情况,没有任何事务

// 方法A
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.NEVER)
    public void insertB(){
        // do something
    }

第一种情况,A有事务 ,这种情况会抛异常: IllegalTransactionStateException 

  // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.NEVER)
    public void insertB(){
        // do something
    }

7、NESTED   

如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按  REQUIRED 属性执行。 

大白话:如果哥哥吃苹果吃出毛病了(代码抛异常了),那我和哥哥都会回到原点(回滚),如果我吃苹果吃出毛病了(代码抛异常了),那就只有我会回到原点(回滚);

代码举例,第一种情况,A方法抛出异常,A和B都会回滚

 // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something
        // 抛出异常
        throw new Exception();
    }

    // 方法B
    @Transactional(propagation = Propagation.NESTED)
    public void insertB(){
        // do something
    }

 第二种情况,B方法抛出异常,只回滚B事务;

 // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        insertB();
        // do something

    }

    // 方法B
    @Transactional(propagation = Propagation.NESTED)
    public void insertB(){
        // do something
        throw new Exception();
    }

当我们使用上面第二种情况的代码的时候,其实内部的伪代码其实是这样的

    // 方法A
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertA(){
        // do something
        try{
            insertB();
        } catch (Exception e){
            e.printStackTrace();
        }
        // do something
    }

    // 方法B
    @Transactional(propagation = Propagation.NESTED)
    public void insertB(){
        // do something
        throw new Exception();
    }

 

到这里事务传播行为就介绍完了,如果还是不懂,那就得请个脑科大夫看看了!!

 

以上是关于图解spring中七种事务传播行为 终于有人讲明白了的主要内容,如果未能解决你的问题,请参考以下文章

Spring中事务传播行为

Spring事务传播行为详解(示例版)

事务总结

Spring事务的七种传播行为

Spring事务的七种传播行为

Spring事务的七种传播行为