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

发布时间:2022-03-01 11:42:12 作者:yexindonglai@163.com 阅读(555)

 

什么是传播行为?

  默认情况下,只有一个事务,所有的修改操作都在一个事务里面,要么一起提交,要么一起回滚,这没什么问题。但要是有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  

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

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

举例代码

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.REQUIRED)
  10. public void insertB(){
  11. // do something
  12. }

2、SUPPORTS 

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

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

使用举例

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.SUPPORTS)
  10. public void insertB(){
  11. // do something
  12. }

 

3、REQUIRES_NEW  

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

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

使用举例

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.REQUIRES_NEW)
  10. public void insertB(){
  11. // do something
  12. }

4、MANDATORY 

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

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

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

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

第二种情况,有当前事务

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.MANDATORY)
  10. public void insertB(){
  11. // do something
  12. }

5、NOT_SUPPORTED  

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

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

代码举例

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.NOT_SUPPORTED)
  10. public void insertB(){
  11. // do something
  12. }

6、NEVER 

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

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

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

  1. // 方法A
  2. public void insertA(){
  3. // do something
  4. insertB();
  5. // do something
  6. }
  7. // 方法B
  8. @Transactional(propagation = Propagation.NEVER)
  9. public void insertB(){
  10. // do something
  11. }

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

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.NEVER)
  10. public void insertB(){
  11. // do something
  12. }

7、NESTED   

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

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

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

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. // 抛出异常
  8. throw new Exception();
  9. }
  10. // 方法B
  11. @Transactional(propagation = Propagation.NESTED)
  12. public void insertB(){
  13. // do something
  14. }

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

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. insertB();
  6. // do something
  7. }
  8. // 方法B
  9. @Transactional(propagation = Propagation.NESTED)
  10. public void insertB(){
  11. // do something
  12. throw new Exception();
  13. }

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

  1. // 方法A
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public void insertA(){
  4. // do something
  5. try{
  6. insertB();
  7. } catch (Exception e){
  8. e.printStackTrace();
  9. }
  10. // do something
  11. }
  12. // 方法B
  13. @Transactional(propagation = Propagation.NESTED)
  14. public void insertB(){
  15. // do something
  16. throw new Exception();
  17. }

 

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

 

关键字Spring