Mysql | 事务的传播

1,287 阅读2分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

一、事务的传播行为

概念

  • spring支持7种事务传播行为,确定客户端和被调用端的事务边界
  • 多个具有事务控制的service的相互调用时所形成的复杂的事务边界控制
  • 事务的传播行为是Spring框架独有的事务增强特性,它不属于事务实际提供方数据库行为

分类

img

外围方法事务

  • 外围方法抛出异常,这两种方法的事务都会被回滚

    • NESTED
    • REQUIRED
  • REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。
  • 内部方法事务

    • 内部方法事务回滚而不影响外围方法事务

      • NESTED
      • REQUIRES_NEW
    • NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务

二、事务错误使用异常场景

场景,执行带事务的语句时,报以下的错误。

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

代码如下 : img

分析

methodA与methodB共用一个事务,methodB将事务标志为回滚,methodA中commit这个事务,然后,出现事务已经被标志回滚(methodB标志的)的异常信息。

解决方案

  • methodA与methodB在逻辑上不应该属于同一个事务,那么将methodB的事务传播属性修改为PROPAGATION_REQUIRES_NEW,这样,执行methodB时,会创建一个新的事务,不影响methodA中的事务
  • 业务A与业务B在业务逻辑上就应该属于同一个事务,那么将methodA中的try catch去掉
  • methodB的失败与否不能影响methodA的事务提交,将methodB的事务传播特性修改成PROPAGATION_NESTED,即失败不影响外部事务,成功则和外部事务一起提交。