本文是基于seata的AT模式来谈2pc的实现
在两阶段提交中,分布式事务角色有:协调者、发起者与参与者
TC:事务协调者,在seata中就是指seata-server。
TM:事务的发起者,一般是入口方法,需要发起全局事务,和负责本地事务的提交和回滚。比如说订单服务中下单逻辑。
RM:事务的参与者,只需要负责好本地事务的提交和回滚,比如说库存服务中的扣减库存逻辑。
两阶段提交将事务的提交分为两个阶段,分别是准备阶段和提交阶段。
以订单服务、库存服务来描述两阶段提交在使用seata框架下的流程。
在事务准备阶段
订单服务作为事务的TM,也就是事务的发起者,在调用下单的时候,会向TC发起请求,以获取全局事务ID,这里称为XID。
订单服务会调用库存服务进行扣减库存,这个时候,seata框架会将XID传递下去,在feign中,是通过请求头方式进行传递。
当库存服务(RM)接收到订单服务调用后,库存服务会执行本地事务,seata会拦截数据源的操作,在这个过程中,会生成前置镜像SQL和后置镜像SQL(就是操作前和操作后查询一下数据库),将数据插入到seata框架所有的undo_log中(注意,这个不是mysql数据库的undo_log,而是切切实实的一张表)。
库存服务操作本地事务完成后(注意,在这里事务已经提交了),会向TC上报事务状态。
在事务的提交或者回滚阶段
如果需要进行提交
在订单服务完成了全部相关接口调用后,需要作为TM向TC发起全局事务提交的请求。
TC在接收TM的全局事务提交的请求后,会异步驱动全部RM(订单和库存服务)进行事务提交。需要注意,这里是异步驱动,非同步。
在事务提交完成后,会删除undo_log中的数据。
如果需要进行回滚
会回滚的前提是,有任何一个RM在执行过程中出现异常,TM就会向TC发起回滚的请求。
RM会根据undo_log中记录的信息回滚本地事务。注意,不是直接rollback。