【深入理解SpringCloud微服务】Seata简介与四种事务模式

Seata简介

Seata是Alibaba开源的一个分布式事务组件,可以实现分布式环境下跨服务的事务一致性。

Seata三种角色

Seata包含三种角色:TM、RM、TC。

  • TM(Transaction Manager):事务管理器。
  • RM(Resource Manager):资源管理器。
  • TC(Transaction Coordinator):事务协调者。

他们的作用如下图:

在这里插入图片描述

这么说好像还是不太明白,我画个图就清晰了。

我们以XA事务模式为例。

在这里插入图片描述

  1. 在XA事务一阶段,TM请求TC开启全局事务。
  2. TM请求第一个RM执行业务逻辑,如果TM和TC是同一个服务,那么这个请求其实就是个本地调用,如果不是的话,那么就是RPC远程调用。
  3. RM先执行SQL,然后请求TC注册分支事务,然后本地执行prepare操作,然后上报分支事务状态
  4. 第一个RM请求第二个RM,第二个RM也是和第一个RM一样来一套。

如果一切顺利,TM在二阶段就会进行全局事务提交。

在这里插入图片描述

TC接收到TM的全局事务提交请求后,会通知各RM进行分支事务提交。各RM接收到TC的提交分支事务通知后,会提交本地事务。

RM执行时不管那一步出问题,都会报错,然后TM就会catch到报错信息,在二阶段进行全局事务回滚。

在这里插入图片描述
TC接收到TM的全局事务回滚请求后,会通知各RM进行分支事务回滚。各RM接收到TC的回滚分支事务通知后,会回滚本地事务。

Seata两个注解

Seata提供了两个注解@GlobalTransactional和@GlobalLock:

  • @GlobalTransactional表示声明开启一个全局事务。
  • @GlobalLock执行当前操作需要检查全局锁。

在这里插入图片描述

如果一个服务的某个方法被标注了@GlobalTransactional,并且该服务又是服务调用链的起点,那么当前服务就是TM,要负责进行全局事务的开启、提交、回滚等一系列操作。

在这里插入图片描述

而如果一个服务的某个方法被标注了@GlobalLock注解,则执行本地事务时,在获取到本地锁执行了本地事务的操作后,先不提交,会请求TC检查全局锁是否存在,如果存在,说明当前有全局事务正修改同一条记录,因此当前操作回滚,之后全局锁不存在,才提交本地事务,然后释放本地锁。

在这里插入图片描述

@GlobalLock注解不会开启全局事务,但是可以防止与全局事务的并发读写冲突。

Seata四种事务模式

AT

流程

在这里插入图片描述
AT模式一阶段流程:

  1. TM请求TC开启全局事务
  2. TM调用RM执行(第一个RM),如果是TM和RM是同一个服务则是本地调用,否则就是远程调用
  3. RM生成前置镜像(当前记录修改前的快照)、执行sql、生成后置镜像(当前记录修改后的快照)、根据前置镜像和后置镜像生成undolog并插入(注意:这个undolog不是数据库的undolog日志,而是seata搞的一个undolog表的记录,用于回滚已提交的本地事务)
  4. RM请求TC注册分支事务
  5. RM把执行的sql已经插入的undolog一并提交
  6. RM请求TC上报分支事务状态
  7. 如果调用链还有后续,则前一个RM调用后一个RM,后一个RM也是这样来一套

如果一切顺利,那么TM在二阶段就会提交全局事务。

在这里插入图片描述

AT模式二阶段(提交)流程:

  1. TM请求TC提交全局事务
  2. TC通知RM提交分支事务
  3. RM所谓的提交分支事务,就是异步删除一阶段生成的undolog,其他啥也没干

但是如果一阶段在调用链上有执行报错的话,就会被TM捕获到,然后TM在二阶段就会发起全局事务回滚。

在这里插入图片描述

AT模式二阶段(回滚)流程:

  1. TM请求TC回滚全局事务
  2. TC通知RM回滚分支事务
  3. RM开启本地事务,查询一阶段生成的undolog,根据undolog解析生成回滚语句,然后执行该回滚语句并提交

使用

Seata的AT模式使用非常简单,只需在需要开启全局事务的地方使用@GlobalTransactional注解。但是为了防止其他操作与当前全局事务出现并发读写冲突的情况,可以在@GlobalTransactional注解修饰的接口触发的调用链上的每个接口,使用@GlobalLock修饰。

在这里插入图片描述

TCC

流程

在这里插入图片描述

TCC模式一阶段:

  1. TM请求TC开启全局事务
  2. TM调用RM执行(第一个RM),如果是TM和RM是同一个服务则是本地调用,否则就是远程调用
  3. RM请求TC注册分支事务
  4. RM执行自定义的prepare操作
  5. RM请求TC上报分支事务状态
  6. 如果调用链还有后续,则前一个RM调用后一个RM,后一个RM也是这样来一套

如果一切顺利,那么TM在二阶段就会提交全局事务。

在这里插入图片描述

TCC二阶段(提交)流程:

  1. TM请求TC提交全局事务
  2. TC通知RM提交分支事务
  3. RM执行自定义的commit操作

但是如果一阶段在调用链上有执行报错的话,就会被TM捕获到,然后TM在二阶段就会发起全局事务回滚。

在这里插入图片描述

TCC二阶段(回滚)流程:

  1. TM请求TC回滚全局事务
  2. TC通知RM回滚分支事务
  3. RM执行自定义的rollback操作

使用

TCC的使用比AT模式复杂一点点。

@GlobalTransactional
public String doTransactionCommit(){
	// rpc远程调用
    tccActionOne.prepare(null,"one");
    // 本地调用
    tccActionTwo.prepare(null,"two");
}

比如上面的doTransactionCommit方法需要开启全局事务,那么还是需要@GlobalTransactional注解修饰。然后doTransactionCommit()里面调用了tccActionOne.prepare(null,“one”)和tccActionTwo.prepare(null,“two”)两个方法,假设tccActionOne.prepare(null,“one”)是远程调用,tccActionTwo.prepare(null,“two”)是本地调用。

public interface TccActionOne {
    @TwoPhaseBusinessAction(name = "DubboTccActionOne", commitMethod = "commit", rollbackMethod = "rollback")
    public boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "a") String a);
    public boolean commit(BusinessActionContext actionContext);
    public boolean rollback(BusinessActionContext actionContext);
}

然后两个接口的prepare方法上,需要添加@TwoPhaseBusinessAction。@TwoPhaseBusinessAction的name属性指定TCC的beanName,commitMethod属性指定commit操作执行的方法,rollback操作指定执行的rollback操作方法,使用@BusinessActionContextParameter可以把指定参数存入BusinessActionContext,那么二阶段就能从BusinessActionContext中取到。

@LocalTCC
public interface TccActionTwo {
    @TwoPhaseBusinessAction(name = "TccActionTwo", commitMethod = "commit", rollbackMethod = "rollback")
    public boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "a") String a);
    public boolean commit(BusinessActionContext actionContext);
    public boolean rollback(BusinessActionContext actionContext);
}

由于TccActionTwo是本地调用,因此在TccActionTwo上还要添加@LocalTCC注解。

在这里插入图片描述

SAGA

SAGA适合用于长事务,在SAGA事务模式中,每个事务参与者都提交本地事务,如果其中一个参与者提交失败,则会沿着调用链执行反向补偿。

在这里插入图片描述

每个正向服务和反向补偿都是一个本地事务,执行完会立刻提交。每个正向服务和反向服务都需要业务开发自己实现。

seata的saga事务模式是基于状态机引擎实现的。

在这里插入图片描述

使用saga模式,我们首先自己要画好一个状态流转图,然后根据状态流转图按照seata的规则定义描述状态图的json文件。json描述文件将交给状态机引擎执行,执行过程中的状态流转将按照json描述文件进行。

XA

XA模式一阶段:

在这里插入图片描述

XA模式二阶段(提交):

在这里插入图片描述

XA模式二阶段(回滚):

在这里插入图片描述

流程

XA的流程上面已经说了,这里不再重复描述。

使用

XA模式的使用方式是根据AT模式一样的,唯一区别就是代理数据源换成DataSourceProxyXA类型

public class DataSourceProxy {
    @Bean("dataSourceProxy")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        return new DataSourceProxyXA(druidDataSource);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值