事务管理之传播机制

常见的是Spring管理事务,所以以Spring事务传播机制为例

参考资料:

https://blog.csdn.net/qq_26323323/article/details/81908955

https://www.cnblogs.com/myseries/p/10800430.html

1 事务传播概述

事务传播: 当一个事务方法被另一个事务方法调用时,必须指定事务怎么传播.具体选择传播行为如下表:

传播行为说明
propagation_requierd如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中(Spring事务传播默认)
propagation_supports支持当前事务,如果没有当前事务,就以非事务方法执行
propagation_mandatory使用当前事务,如果没有当前事务,就抛出异常
propagation_required_new新建事务,如果当前存在事务,把当前事务挂起
propagation_not_supported以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
propagation_never以非事务方式执行操作,如果当前事务存在则抛出异常
propagation_nested如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作

2 事务详情

Spring事务机制包括,编程式和声明式, 在工作中常用的是声明式,即通过添加事务注解,使用Spring的AOP切面编程解析的方式.下面案列以注解形式说明.

1 PROPAGATION_REQUIRED

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

//事务属性 PROPAGATION_REQUIRED 
methodA{ 
  …… 
  methodB(); 
  …… 
}
 
//事务属性 PROPAGATION_REQUIRED 
methodB{ 
   …… 
}

1 单独调用方法B
metodB(); 

编程式代码:

Connection con=null; 
    try{ 
        // 建立连接
        con = getConnection(); 
        con.setAutoCommit(false); 
        // 方法调用
        methodB(); 
        // 提交事务
        con.commit(); 
    } 
    Catch(RuntimeException ex){ 
        // 回滚事务
        con.rollback();   
    } 
    finally{ 
    // 释放资源
    closeCon(); 
    } 

在调用methodB方法时,获得同一个相同的连接,没有存在的事务,就新建一个事务维护

2 方法A调用方法B
methodA{
    ...
    methodB();   
    ...
}

编程式代码:

Connection con=null; 
    try{ 
        // 建立连接
        con = getConnection(); 
        con.setAutoCommit(false); 
        // 方法调用
        methodA(); 
        // 提交事务
        con.commit(); 
    } 
    Catch(RuntimeException ex){ 
        // 回滚事务
        con.rollback();   
    } 
    finally{ 
    // 释放资源
    closeCon(); 
    } 

在调用方法A时,没有事务,新建一个事务维护. 方法A中调用方法B时, 因为已存在事务,所以方法B加入到当前事务中,不新建事务,且事务一旦回滚,方法A和方法B中,状态都会回滚.

2 PROPAGATION_SUPPORTS

如果存在一个事务,支持当前事务,如果没有当前事务,就以非事务方法执行.

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
  methodB(); 
}
 
//事务属性 PROPAGATION_SUPPORTS 
methodB(){ 
  …… 
}
1 单独调用方法B
metodB(); 

单独调用方法B,因为当前没有事务,所以以非事务执行.

2 方法A调用方法B
methodA{
    ...
    methodB();   
    ...
}

编程式代码:

Connection con=null; 
    try{ 
        // 建立连接
        con = getConnection(); 
        con.setAutoCommit(false); 
        // 方法调用
        methodA(); 
        // 提交事务
        con.commit(); 
    } 
    Catch(RuntimeException ex){ 
        // 回滚事务
        con.rollback();   
    } 
    finally{ 
    // 释放资源
    closeCon(); 
    } 

在调用方法A时,没有事务,新建一个事务维护. 方法A中调用方法B时, 因为已存在事务,所以方法B加入到当前事务中,且事务一旦回滚,方法A和方法B中,状态都会回滚.

如果方法A中没有事务,则方法B以非事务执行.

3 PROPAGATION_MANDATORY

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
    methodB(); 
}
 
//事务属性 PROPAGATION_MANDATORY 
methodB(){ 
    …… 
}
1单独调用方法B

单独调用方法B时,当前没有事务,会抛出异常throw new IllegalTransactionStateException

2方法A调用方法B
methodA{
    ...
    methodB();   
    ...
}

​ 如果方法A有事务,在调用方法B时,会加入到当前事务中; 如果方法A没有事务,则会抛出上述异常.

4 PROPAGATION_REQUIRED_NEW

创建一个新的事务。如果有事务已经存在,则将这个存在的事务挂起.

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
   doSomeThingA(); 
   methodB(); 
   doSomeThingB(); 
}
 
//事务属性 PROPAGATION_REQUIRES_NEW 
methodB(){ 
   …… 
}
1单独调用方法B

当前没有事务,调用方法B会创建一个新的事务.

2方法A调用方法B
 methodA(); 

编程式代码:

  TransactionManager tm = null; 
try{ 
  // 获得一个JTA事务管理器 
    tm = getTransactionManager(); 
    // 开启一个新的事务 
    tm.begin();
    Transaction ts1 = tm.getTransaction(); 
    doSomeThing(); 
    // 挂起当前事务 
    tm.suspend();
    try{ 
      // 重新开启第二个事务 
      tm.begin();
      Transaction ts2 = tm.getTransaction(); 
      methodB(); 
      // 提交第二个事务 
      ts2.commit();
   } 
  Catch(RunTimeException ex){ 
      // 回滚第二个事务 
      ts2.rollback();
  } 
  finally{ 
     // 释放资源 
   } 
    // methodB执行完后,复恢第一个事务 
    tm.resume(ts1); 
doSomeThingB(); 
    // 提交第一个事务 
    ts1.commit();
} 
catch(RunTimeException ex){ 
    // 回滚第一个事务 
   ts1.rollback();
} 
finally{ 
   // 释放资源 
} 

在双层嵌套的事务中, 外层和内层的事务, 互相独立,互不影响.使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作为事务管理器。

5 PROPAGATION_NOT_SUPPORTED

总是非事务地执行,并挂起任何存在的事务.(需要使用JtaTransactionManager作为事务管理器)

1 单独调用方法B

当前没有事务,调用方法B会以非事务执行;当前有事务,方法B同样以非事务执行.

2方法A调用方法B
methodA(); 

编程式代码:

  TransactionManager tm = null; 
try{ 
  // 获得一个JTA事务管理器 
    tm = getTransactionManager(); 
    // 开启一个新的事务 
    tm.begin();
    Transaction ts1 = tm.getTransaction(); 
    doSomeThing(); 
    // 挂起当前事务 
    tm.suspend();

      methodB(); 

    // methodB执行完后,复恢第一个事务 
    tm.resume(ts1); 
	doSomeThingB(); 
    // 提交第一个事务 
    ts1.commit();
} 
catch(RunTimeException ex){ 
    // 回滚第一个事务 
   ts1.rollback();
} 
finally{ 
   // 释放资源 
} 

6 PROPAGATION_NEVER

总以非事务地执行,如果存在一个活动事务,则抛出异常.

1 单独调用方法B

当前没有事务,调用方法B会以非事务执行;当前有事务,则抛出异常.

2 方法A调用方法B

方法A没有事务,调用方法B会以非事务执行;方法A有事务,则抛出异常.

7 PROPAGATION_NESTED

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

(使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;而nestedTransactionAllowed属性值默认为false;)

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
   doSomeThingA(); 
   methodB(); 
   doSomeThingB(); 
}
 
//事务属性 PROPAGATION_NESTED 
methodB(){ 
  …… 
}
1 单独调用方法B

单独调用方法A,相当于REQUIRED属性,即Spring默认的属性.

2 方法A调用方法B
Connection con = null; 
Savepoint savepoint = null; 
try{ 
   con = getConnection(); 
   con.setAutoCommit(false); 
   doSomeThingA(); 
   savepoint = con2.setSavepoint(); 
   try{ 
       methodB(); 
   }catch(RuntimeException ex){ 
      con.rollback(savepoint); 
   } 
   finally{ 
     //释放资源 
  }
 
   doSomeThingB(); 
   con.commit(); 
} 
catch(RuntimeException ex){ 
  con.rollback(); 
} 
finally{ 
   //释放资源 
} 

当调用方法B时,设置回滚点, 调用方法B,如果调用失败,则回滚到之前的状态. 代码继续向下运行.

如果后续代码出现问题,则会进行全部的回滚,包括方法B.

即内层方法B调用错误,只会回滚到方法B之前的状态,不会影响方法B外面的内容.

外层方法调用错误. 会导致全部回滚,即方法A中所有和方法B.

8 总结

​ Spring的默认事务是PROPAGATION_REQUIRED.如果业务中的方法都添加了事务注解,说明方法都配Spring的事务管理,在整个调用的链路中,所有方法都是在同一个事务中.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值