Spring AOP—声明式事务中的传播特性(详细记录)

Spring声明式事务中的传播特性(详细)

1.事务的传播特性:

事务的传播特性指的是:当一个事务方法被另一个事务方法调用时,这个事务应该如何进行控制。

7种传播特性:

在这里插入图片描述

2、REQUIRED属性
  • 使用: @Transactional(propagation = Propagation.REQUIRED)
  • 描述:如果有事务在运行,当前方法就在这个事务内运行,否则,就启动一个新的事务,并在它的事务中运行。
1、方法a和方法b都不进行事务添加,只是普通方法,方法c是事务方法

方法c调用方法a和方法b

//事务方法c
c(){
        a();//普通方法
        b();//普通方法
    }

结果:方法b、事务方法c、只要其中一个出现一异常,事务将会回滚。

2、方法a和方法b都设置为:REQUIRED,方法c是事务方法

先用表格展示,后面进行演示:

方法a和方法b都设置为:REQUIRED,方法c是事务方法,方法c调用方法a和方法b

@Transactional(propagation = Propagation.REQUIRED)
a(){};

@Transactional(propagation = Propagation.REQUIRED)
b(){};

//事务方法c
@Transactiona
c(){
        a();
        b();
    }

表格:

方法a方法b方法c结果
正常正常正常正常
异常正常正常全部回滚
正常异常正常全部回滚
异常异常正常全部回滚
正常正常异常全部回滚

总结:可见三个方法在同一个事务中运行,若其中一个异常,则会回滚。

演示:

  1. 事务方法c调用方法a(正常)和方法b(正常)

    //事务方法c
    c(){
            a();//正常
            b();//正常
        }
    

    结果:正常运行

  2. 事务方法c调用方法a(异常)和方法b(正常)

    //事务方法c
    c(){
            a();//异常
            b();//正常
        }
    

    结果:全部方法回滚;

  3. 事务方法c调用方法a(正常)和方法b(异常)

    //事务方法c
    c(){
            a();//正常
            b();//异常
        }
    

    结果:全部回滚

  4. 事务方法c调用方法a(异常)和方法b(异常)

    //事务方法c
    c(){
            a();//异常
            b();//异常
        }
    

    结果:全部回滚

  5. 事务方法c(异常)调用方法a(正常)和方法b(正常)

    //事务方法c
    c(){
            int i=1/0;//异常,无论异常在哪个位置
            a();//正常
            b();//异常
        }
    

    结果:无论事务c中的异常在哪个地,都全部回滚。

    总结:方法a和方法b都设置为:REQUIRED,方法c是事务方法。调用方法a和方法b,两个方法都会在c方法的事务中运行,三者只要一个一异常,则全部回滚。

3、方法a和方法b都设置为:REQUIRED,方法c是普通方法

此时,方法a和方法b都将各自新启动事务并各自执行

先用表格展示,后面进行演示:

方法a和方法b都设置为:REQUIRED,方法c不是事务方法,方法c调用方法a和方法b

@Transactional(propagation = Propagation.REQUIRED)
a(){};

@Transactional(propagation = Propagation.REQUIRED)
b(){};

//普通方法c
c(){
        a();
        b();
    }
方法a方法b方法c结果
正常正常正常全部正常
异常正常正常ac回滚,b不回滚
正常异常正常ac回滚,b不回滚
异常异常正常全部回滚
正常正常异常c回滚,ab不回滚

总结:c是普通方法,则a和b会各自新启动事务,各自事务互不影响

  1. 普通方法c调用方法a(正常)和方法b(正常)

    //普通方法c
    c(){
            a();//正常
            b();//正常
        }
    

    结果:正常运行

  2. 普通方法c调用方法a(异常)和方法b(正常)

    //普通方法c
    c(){
            a();//异常
            b();//正常
        }
    

    结果:a回滚,c回滚,b不回滚。

  3. 普通方法c调用方法a(正常)和方法b(异常)

    //普通方法c
    c(){
            a();//正常
            b();//异常
        }
    

    结果:b回滚,c回滚,a不回滚

  4. 普通方法c调用方法a(异常)和方法b(异常)

    //普通方法c
    c(){
            a();//异常
            b();//异常
        }
    

    结果:a、b、c都回滚

  5. 普通方法c(异常)调用方法a(正常)和方法b(正常)

    //普通方法c
    c(){
            int i=1/0;//无论异常在哪个位置
            a();//正常
            b();//正常
        }
    

    结果:c回滚,a不回滚,b不回滚

总结:方法a和方法b都设置为:REQUIRED,方法c是普通方法。方法c调用方法a和方法b,由于方法c不是事务方法,方法a和方法b都回各自新建事务。两者互不影响

4、方法a和方法b都设置为:REQUIRED,方法c是事务方法,进行异常捕获
  1. a(或b)有异常,在c中进行捕获。全部回滚。

  2. a(或b)有异常,在a(或b)中捕获,a(或b)回滚,其他不回滚

  3. a,b正常,c中有异常并捕获,全部回滚

3.REQUIRED_NEW属性
  • 使用: @Transactional(propagation = Propagation.REQUIRED_new)
  • 描述:当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务在运行,则将他挂起。
  • 理解:如果调用该方法是事务方法,那么该方法的事务将挂起,启动新事务,在自己的事务内运行,不受挂起事务的影响,但是挂起事务会收到新启动事务的影响
1、方法a和方法b都设置为:REQUIRED_NEW,方法c是事务方法

先用表格展示,后面进行演示:

方法a和方法b都设置为:REQUIRED_NEW,方法c是事务方法,方法c调用方法a和方法b

@Transactional(propagation = Propagation.REQUIRED_NEW)
a(){};

@Transactional(propagation = Propagation.REQUIRED_NEW)
b(){};

//事务方法c
@Transactiona
c(){
        a();
        b();
        //int i=1/0;
    }
方法a方法b方法c结果
正常正常正常正常
异常正常正常a,c回滚,b不回滚
正常异常正常b,c回滚,a不回滚
异常异常正常全部回滚
正常正常异常c回滚,ab不回滚

总结:方法a和方法b都会启动新事物,不会相互影响,也不会受c事务的影响,但是c事务会受到a和b事务结果的影响。

演示:

  1. 事务方法c调用方法a(正常)和方法b(正常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED_NEW)
    b(){};
    
    //事务方法c
    @Transactiona
    c(){
            a();//正常
            b();//正常
        }
    

    结果:正常运行

  2. 事务方法c调用方法a(异常)和方法b(正常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED_NEW)
    b(){};
    
    //事务方法c
    @Transactiona
    c(){
            a();//异常
            b();//正常
        }
    

    结果:a回滚,c回滚,b不回滚

  3. 事务方法c调用方法a(正常)和方法b(异常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED_NEW)
    b(){};
    
    //事务方法c
    @Transactiona
    c(){
            a();//正常
            b();//异常
        }
    

    结果:b回滚,c回滚,a不回滚

  4. 事务方法c调用方法a(异常)和方法b(异常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED_NEW)
    b(){};
    
    //事务方法c
    @Transactiona
    c(){
            a();//异常
            b();//异常
        }
    

    结果:全部回滚

  5. 事务方法c(异常)调用方法a(正常)和方法b(正常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED_NEW)
    b(){};
    
    //事务方法c
    @Transactiona
    c(){
            int i=1/0;
            a();//正常
            b();//正常
            
        }
    

    结果:c回滚,a,b不回滚

    总结:从上面的案例是可以发现,只要方法a和方法b其中一个异常,事务c都会回滚,但是c异常,a和b都不会回滚。可见新启动的事务(a,b)不受挂起事(c)务的影响,但是新启动的事务(a,b)会影响挂起的事务(c).

2、方法a设置为REQUIRED_NEW,方法b都设置为:REQUIRED,方法c是事务方法

先用表格展示,后面进行演示:

法a设置为REQUIRED_NEW,方法b都设置为:REQUIRED_,方法c是事务方法。方法c调用方法a和方法b

@Transactional(propagation = Propagation.REQUIRED_NEW)
a(){};

@Transactional(propagation = Propagation.REQUIRED)
b(){};
//事务方法c
@Transactiona
c(){
        a();
        b();
        //int i=1/0;
    }
方法a方法b方法c方法a和b的先后顺序结果
正常正常正常a在b上方(a先执行)正常运行
异常正常正常a在b上方(a先执行)全部回滚
正常异常正常a在b上方(a先执行)a不回滚,b,c回滚
异常异常正常a在b上方(a先执行)全部回滚
正常正常异常a在b上方(a先执行)a不回滚,b,c回滚
正常正常正常b在a上方(b先执行)正常运行
异常正常正常b在a上方(b先执行)全部回滚
正常异常正常b在a上方(b先执行)a不回滚,b,c回滚
异常异常正常b在a上方(b先执行)全部回滚
正常正常异常b在a上方(b先执行)a不回滚,b,c回滚

由此可见,a是新启动事务,b是直接入c的事务中,a回不回滚和a,b的先后顺序无关。a是新启动的事务,不会被其他事务影响。但是a会影响c的事务。

由表中知道与顺序无关,只演示一种顺序:

  1. 事务方法c(正常)调用方法a(正常)和方法b(正常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED)
    b(){};
    //事务方法c
    @Transactiona
    c(){
            a();//正常
            b();//正常
        }
    

    结果:正常运行

  2. 事务方法c(正常)调用方法a(异常)和方法b(正常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED)
    b(){};
    //事务方法c
    @Transactiona
    c(){
            a();//异常
            b();//正常
        }
    

    结果:全部回滚

  3. 事务方法c(正常)调用方法a(正常)和方法b(异常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED)
    b(){};
    //事务方法c
    @Transactiona
    c(){
            a();//正常
            b();//异常
        }
    

    结果:b,c回滚,a不回滚

  4. 事务方法c(正常)调用方法a(异常)和方法b(异常)

    @Transactional(propagation = Propagation.REQUIRED_NEW)
    a(){};
    
    @Transactional(propagation = Propagation.REQUIRED)
    b(){};
    //事务方法c
    @Transactiona
    c(){
            a();//正常
            b();//异常
        }
    

    结果:全部回滚

  5. 事务方法c(异常)调用方法a(正常)和方法b(正常)

   @Transactional(propagation = Propagation.REQUIRED_NEW)
   a(){};
   
   @Transactional(propagation = Propagation.REQUIRED)
   b(){};
   //事务方法c
   @Transactiona
   c(){
           a();//正常
           b();//正常
           int i=1/0;
       }

结果:b,c回滚,a不回滚。

总结:a是新启动的事务,b会加入c中的事务,a事务启动时,c事务将会挂起。a事务不会收c事务影响,但是c事务会受到a事务的影响,

3、方法a设置为REQUIRED_NEW,方法b都设置为:REQUIRED_,c调用a和b。进行异常捕获
  1. a异常,在c中捕获–a回滚,b,c不会回滚
  2. a异常,在a中捕获–a回滚,b,c不会回滚
  3. c异常,在c中捕获–a回滚,b,c回滚
4、SUPPROTS属性
  • 使用: @Transactional(propagation = Propagation.SUPPROTS)
  • 描述:如果有事务在运行,当前的方法在该事务中运行,否则,它可以不运行在事务中。
  • 比较容易理解
1、方法a设置为REQUIRED,方法b都设置为:SUPPORTS,事务c调用a和b
  1. 因为c是事务,则a和b一起运行在c的事务中,重要其中一个错误,全部回滚。
2、方法a设置为REQUIRED,方法b都设置为:SUPPORTS,普通c调用a和b
  1. 由于c是普通方法,则a会新启动事务,a,c没有运行在事务中。a不受b,c影响,但是b,c受各自的顺序和a位置的影响。
5、NOT_SUPPROTES属性
  • 使用: @Transactional(propagation = Propagation.NOT_SUPPROTES)
  • 描述:当前方法不应该运行在事务中,如果有运行的事务,则将他挂起
  • 比较容易理解
6、NAVER属性
  • 使用: @Transactional(propagation = Propagation.NAVER)
  • 描述:当前方法不应该运行在事务中,如果运行在事务中,则抛出异常
  • 比较容易理解,一般与NOT_SUPPROTES属性作比较
7、MANDAFORY属性
  • 使用: @Transactional(propagation =MANDAFORY)
  • 描述:当前方法必须运行在事务中,如果没有运行的事务,就抛出异常。
  • 比较容易理解
8、NESTED属性
  • 使用: @Transactional(propagation =NESTED)
  • 描述:如果有事务在运行,当前方法就在该事务的嵌套事务内运行,否则就启动一个新事物,并在它自己的事务内云进行
  • 理解:如果外层方法中有事务,那么直接创建一个保存点,如果外层方法没有事务,那么就创建一个新的事务,后续操作中如果没有异常情况,那么会清除保存点信息,并且在外层事务中进行提交操作,如果内层方法中存在异常情况,那么会回滚到保存点,外层方法事务会直接进行回滚,如果外层方法中存在异常情况,那么会内层方法会正常执行,并且执行完毕之后释放保存点,并且外层方法事务会进行回滚
1.法a设置为NESTED,方法b都设置为:REQUIRED,方法c是事务方法。方法c调用方法a和方法b
@Transactional(propagation = Propagation.NESTED)
a(){};

@Transactional(propagation = Propagation.REQUIRED)
b(){};
//事务方法c
@Transactiona
c(){
        a();
        b();
        //int i=1/0;
    }
方法a方法b方法c结果
正常正常正常正常运行
异常正常正常全部回滚
正常异常正常全部回滚
异常异常正常全部回滚
正常正常异常全部回滚
2、方法a设置为REQUIRED_NEW,方法b都设置为:REQUIRED_,事务c调用a和b。进行异常捕获
  1. a异常,b正常,在c中捕获a—a回滚,b不回滚。
  2. a,b正常,c中异常并捕获—全部回滚
9总结:

1、事务传播级别是REQUIRED,当checkout()被调用时(假定被另一类中commit()调用),如果checkout()中的代码抛出异常,即便被捕获,commit()中的其他代码都会roll back;

2、是REQUIRES_NEW,如果checkout()中的代码抛出异常,并且被捕获,commit()中的其他代码不会roll back;如果commit()中的其他代码抛出异常,而且没有捕获,不会导致checkout()回滚;

3、是NESTED,如果checkout()中的代码抛出异常,并且被捕获,commit()中的其他代码不会roll back;如果commit()中的其他代码抛出异常,而且没有捕获,会导致checkout()回滚,

4、PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.

5、另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 嵌套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.

6、由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值