Spring事务的传播机制

事务的传播机制:

  • @Transactional(propagation=Propagation.REQUIRED)

如果有事务,那么加入事务,没有的话新建一个(默认情况下)

  • @Transactional(propagation=Propagation.NOT_SUPPORTED)

容器不为这个方法开启事务

  • @Transactional(propagation=Propagation.REQUIRES_NEW)

不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务

  • @Transactional(propagation=Propagation.MANDATORY)

必须在一个已有的事务中执行,否则抛出异常

  • @Transactional(propagation=Propagation.NEVER)

必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)

  • @Transactional(propagation=Propagation.SUPPORTS)

如果其他bean调用这个方法,在其他bean中声明事务,那就用事务。如果其他bean没有声明事务,那就不用事务。

@Transactional(propagation=Propagation.NESTED)

如果当前存在事务,则在嵌套事务内执行,类似数据库事务保存点。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

案例代码

PROPAGATION_REQUIRED

ServiceA {
    @Transactional(propagation = Propagation.REQUIRED)
     void methodA() {
         ServiceB.methodB();
     }
}

ServiceB {
     @Transactional(propagation = Propagation.REQUIRED)
     void methodB() {
     }      
}

ServiceA.methodA 与 ServiceB.methodB 同时成功,否则都失败。 

PROPAGATION_SUPPORTS

ServiceA {
    @Transactional(propagation = Propagation.REQUIRED)
     void methodA() {
         ServiceB.methodB();
     }
}

ServiceB {
     @Transactional(propagation = Propagation.SUPPORTS)
     void methodB() {//依赖调用方法是否事务
     }      
}

假设当前在事务中,即以事务的形式执行。假设当前不在一个事务中,那么就以非事务的形式执行

PROPAGATION_MANDATORY

ServiceA {
    @Transactional(propagation = Propagation.REQUIRED)
     void methodA() {
         ServiceB.methodB();
     }
}

ServiceB {
     @Transactional(propagation = Propagation.MANDATORY)
     void methodB() {//必须事务执行
     }      
}

必须在一个事务中执行。也就是说,他仅仅能被一个父事务调用。否则,他就要抛出异常。ServiceA.methodA()必须以事务执行。

PROPAGATION_REQUIRES_NEW

ServiceA {
    @Transactional(propagation = Propagation.REQUIRED)
     void methodA() {//事务A
         ServiceB.methodB();
     }
}

ServiceB {
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     void methodB() {//事务B
     }      
}

ServiceA.methodA 与ServiceB.methodB是2个独立的事务,互不影响。

当运行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起。ServiceB.methodB会起一个新的事务。等待ServiceB.methodB的事务完毕以后,它才继续运行。

与REQUIRED 的事务差别在于事务的回滚程度。由于ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。假设ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚。ServiceB.methodB是不会回滚的。假设ServiceB.methodB失败回滚,假设他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

PROPAGATION_NOT_SUPPORTED

ServiceA {
    @Transactional(propagation = Propagation.REQUIRED)
     void methodA() {
         ServiceB.methodB();
     }
}

ServiceB {
     @Transactional(propagation = Propagation.NOT_SUPPORTED)
     void methodB() {//非事务方式执行
     }      
}

当前不支持事务。比方ServiceA.methodA的事务级别是PROPAGATION_REQUIRED 。而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起;而它以非事务的状态执行完,再继续ServiceA.methodA的事务。

PROPAGATION_NEVER

ServiceA {
    @Transactional(propagation = Propagation.REQUIRED)
     void methodA() {
         ServiceB.methodB();
     }
}

ServiceB {
     @Transactional(propagation = Propagation.NEVER)
     void methodB() {// 抛出异常
     }      
}

不能在事务中执行。如果ServiceA.methodA的事务级别是PROPAGATION_REQUIRED。 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,那么ServiceB.methodB就要抛出异常了。

PROPAGATION_NESTED

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

当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制。

嵌套事务不能够提交,它必须通过外层事务来完成提交的动作,外层事务的回滚也会造成内部事务的回滚。

PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。

事务的原理

数据库事务XA模型

  • Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
  • Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交全局回滚的决议。
  • Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

事务传播行为就是事务协调器对分支事务的一种控制。

配置方式

<tx:advice id="txAdvice" transaction-manager="txManager"> 
      <tx:attributes>  
      <!--设置所有匹配的方法,然后设置传播级别和事务隔离-->
           <tx:method name="save*" propagation="REQUIRED" /> 
           <tx:method name="add*" propagation="REQUIRED" /> 
           <tx:method name="create*" propagation="REQUIRED" /> 
           <tx:method name="insert*" propagation="REQUIRED" /> 
           <tx:method name="update*" propagation="REQUIRED" /> 
           <tx:method name="merge*" propagation="REQUIRED" /> 
           <tx:method name="del*" propagation="REQUIRED" /> 
           <tx:method name="remove*" propagation="REQUIRED" /> 
           <tx:method name="put*" propagation="REQUIRED" /> 
           <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> 
           <tx:method name="count*" propagation="SUPPORTS" read-only="true" /> 
          <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> 
          <tx:method name="list*" propagation="SUPPORTS" read-only="true" /> 
          <tx:method name="*" propagation="SUPPORTS" read-only="true" /> 
     </tx:attributes> 
</tx:advice> 

<!--开启注解的方式--> 
<tx:annotation-driven transaction-manager="transactioManager" />

参考:Seata实战-分布式事务简介及demo上手

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值