7种事物的传播行为(借鉴大佬,写出自己的理解,通俗易懂)

在讲事务的7种传播行为前可以分享一个个人亲身的小经历,我大三拿到学位证以及成绩合格后和学校申请大四离校外出实习;有屎以来第一次面试就是一家大厂,当时初生牛犊不怕虎,也是不知天高地厚,面试官因为某种原因来的是架构师和项目经理,他们的第一问题就是问我事务的传播行为以及事务的隔离级别,很可惜那家大厂我很向往,但与我无缘;搞技术这行,菜就是原罪,我菜的真实,所以每次谈到事务就让我有所回忆,所以请你打死也要记住这玩意,不要管别人说什么工作中用处大不大,别只局限于眼前的苟且。

进入正题:
一、对传播的初步认识
事务的传播行为,既然是传播行为,那么就要进行传播这个动作,传播就是至少需要两个的,单个个体是不存在传播的。
例如:

 ServiceA {   
     void methodA() {
         ServiceB.methodB();
     }
} 
methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的

二、7种传播行为

-1、PROPAGATION_REQUIRED:支持当前事务,假设当前没有事务。就新建一个事务。

-2、PROPAGATION_SUPPORTS:支持当前事务,假设当前没有事务,就以非事务方式运行。

-3、PROPAGATION_MANDATORY:支持当前事务,假设当前没有事务,就抛出异常。

-4、PROPAGATION_REQUIRES_NEW:新建事务,假设当前存在事务。把当前事务挂起。

-5、PROPAGATION_NOT_SUPPORTED:以非事务方式运行操作。假设当前存在事务,就把当前事务挂起。

-6、PROPAGATION_NEVER:以非事务方式运行,假设当前存在事务,则抛出异常。

-7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

三、理解

ServiceA {   
     void methodA() {
         ServiceB.methodB();
     }
}

ServiceB { 
     void methodB() {
     }      
}

结合以上代码来理解下面内容

1、PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

如果只有一个methodB那么它可以有自己的事务,但是当methodB在methodA中,类似这种嵌套的方式存在事务,
这里我们可以理解为try{}catch{}finally{},方法在try块中,出现异常在catch中都会进行回滚。
可以理解成类似的情形:
try{
conn.setAutoCommit(false);
methodA(){
methodB…. 
}
conn.commit();//提交
 }catch(Exception e){
conn.rollback();//回滚
}finally{
//关闭各种流和关闭连接以及回收入连接池等
}

那么methodB在进行事务时发现自己是在methodA中被调用的,而methodA已经开启了事务,那么methodB就不再自己新开一个事务,当methodA出现事务回滚,尽管methodB已经提交了,还是会和methodA一起进行滚回,体现了事务的一致性和原子性,那么当methodA并没有开启事务,methodB执行了并提交了 ,当到methodA执行发现自己没有事务,它会自己开启一个新的事务,这样尽管methodB提交,methodA也会回滚,methodA与methodB只有其中一个出现了异常也就失败就会被catch到一起进行回滚。

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

如果只存在methodB那么它没有事务则以没有事务的非事务的形式执行,当methodB在其他的方法中被调用,如methodA中被调用,那么当methodA开启了事务那么methodB则以methodA中的事务为准进行事务。

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

如果只存在methodB, 那么它没有事务,则会抛出异常throw new IllegalTransactionStateException(“
Transaction propagation ‘mandatory’ but no existing transaction found”); 当methodB在其他的方法中被调用,如methodA中被调用,那么当methodA开启了事务那么methodB则以methodA中的事务为准进行事务。

4、PROPAGATION_REQUIRES_NEW
新建事务,假设当前存在事务。把当前事务挂起

这里可以把methodB以及methodA理解成开启了两个不相关的事务了,如果methodA开启了PROPAGATION_REQUIRED,而methodB在methodA中,methodB开启了PROPAGATION_REQUIRES_NEW,当methodB执行时,methodA中的事务被挂起了,methodB新建了一个事务,这个事务与methodA中被挂起的事务无关了,也就是说methodB即使失败了回滚了,methodA成功了提交了也不会回滚,同样的,methodA失败了进行了回滚,methodB成功了提交也是可以的。
类似这种情景:
methodA:
try{
connA.setAutoCommit(false);
methodA(){

methodB:
try{
connB.setAutoCommit(false);
methodB(){
}...
connB.commit();//提交
 }catch(Exception e){
connB.rollback();//回滚
}finally{
//关闭各种流和关闭连接以及回收入连接池等
}

}...
connA.commit();//提交
 }catch(Exception e){
connA.rollback();//回滚
}finally{
//关闭各种流和关闭连接以及回收入连接池等
}

5、PROPAGATION_NOT_SUPPORTED
以非事务方式运行操作。假设当前存在事务,就把当前事务挂起

如果只存在methodB,则以非事务的方式进行,当methodB在其他的方法中被调用,如methodA中被调用,那么当methodA开启了事务那么当methodB执行时,methodA中的事务就被挂起,methodB以非事务的方式进行。

6、PROPAGATION_NEVER
以非事务方式运行,假设当前存在事务,则抛出异常

7、PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

如果只存在methodB而它的事务是PROPAGATION_NESTED, 则按REQUIRED属性执行, 当methodB在其他的方法中被调用,如在methodA中被调用,如果methodB失败了methodB会回滚,并不影响到methodA,而methodA回滚了会影响到methodB,methodB在methodA中,但它并没提交,methodB要与methodA保持一致性,一起提交,但methodB回滚不影响到methodA,而methodA回滚了会影响到methodB
类似这种情景:
methodA:
try{
conn.setAutoCommit(false);
methodA(){

methodB:
try{

methodB(){
}...
//内层这里没有提交
//内层这里没有提交
//内层这里没有提交

 }catch(Exception e){
conn.rollback();//回滚
//内层这里回滚
//内层这里回滚
//内层这里回滚
}finally{
//关闭各种流和关闭连接以及回收入连接池等
}

}...
conn.commit();//提交
//外层这里提交
//外层这里提交
//外层这里提交

 }catch(Exception e){
conn.rollback();//回滚
//外层这里也回滚
//外层这里也回滚
//外层这里也回滚
}finally{
//关闭各种流和关闭连接以及回收入连接池等
}
嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚

四、Spring事务的配置
请看我写的AOP__事务配置(简单代码xml配置,注解等)
https://www.cnblogs.com/zhangsonglin/p/10922828.html

借鉴于大佬:
https://blog.csdn.net/qq_38526573/article/details/87898161

https://blog.csdn.net/soonfly/article/details/70305683

加入了大量自己的理解,通俗易懂

猜你喜欢

转载自www.cnblogs.com/zhangsonglin/p/10925933.html