MySQL XA能够实现数据层的分布式事务,解决多个MySQL操作的事务问题,但是我们还需要上次应用层保证指令执行的原子性
可以考虑使用TCC,利用TCC来实现业务层面操作的事务,就可以从数据层面到业务层面,全面理解如何实现分布式事务了
我们拿一个实例来举例,我们需要实现一个订票系统,我们需要考虑一种问题
假如,我从深圳飞往北京,没有直达的机票,需要先定深圳的航班,从深圳飞往上海,然后从上海飞往北京
那么就要保证,要么全部订购成功,要么全不成功,如何操作呢?
那么整体的订票事务,就是一个TCC的流程
什么是TCC,TCC其中包含着两个阶段,预留 确认/撤销,2阶段提交
Try 预留,二阶段提交协议,将系统需要的资源预留,锁定,确保确认操作一定执行成功
Confrim 确认,二阶段提交中,提交执行操作类似,系统最终执行的操作
Cancel,撤销,二阶段提交协议中的回滚操作,系统将撤销预留的而资源,撤销已经执行的预留操作对系统产生的影响
二阶段提交协议和TCC的目标,都是为了实现分布式事务,那么这两者就基本互通,我们来看看TCC的细节
我们拿着上面的场景来看,我们假设深圳航空,上海航空分别都提供了机票预留,确认,撤销三个接口
那么我们的整体事务的操作如下
订票系统调用2个航空公司的机票预留接口,向2个航空公司进行try请求
如果都预留了,就可以进入确认阶段,进行执行确认操作,直接订票
但如果有机票没有预留成功,那怎么办呢,订票系统就需要撤销接口来撤销订票请求
这样就基本实现了
那么如何通过TCC来保证指令执行的原子性呢?
假设我们具有多个操作,我们要保证这些操作可以组合成事务来执行,那么如何做到的呢?
假设这三个操作分别为
1.生成指定URL的图片存储
2.调用内部系统1的接口,禁用指定域名的访问权限
3.通过mysql XA来更新多个数据的数据记录
我们分别使用TCC来解决这个问题,我们给每个操作,实现了各自的预留,确认,撤销操作
对于1操作,
预留操作,生成指定的页面的图片,存储到本地
确认操作,更新操作1状态为完成
撤销操作,删除本地存储的图片
操作3是利用了MySQL XA来更改多个mysql数据库中数据记录,实现数据更新的事务,
预留操作:执行XA START和XA END来准备好事务分支操作,并且调用CA PREPARE,执行二阶段提交协议的提交请求阶段
确认操作,调用XA commit来执行确认操作
撤销操作,调用XA ROLLBACK执行回滚操作,释放Try阶段预留的资源
那么,确认操作可以预留操作的下个操作,撤销而是撤销已经锁定的资源,
那么,操作1 2 3 的预留操作已经执行结束,如果预留都成功了,将执行确认操作,继续向下执行,如果预留操作只是部分执行成功,将进行撤销操作,取消预留操作对系统的影响,可以执行指令执行的原子性了
我们说了TCC,和如何使用TCC来实现分布式事务
那么TCC是一个业务层面的分布式事务协议,XA是数据层面的分布式事务协议,是TCC和XA的最大区别
TCC和业务耦合紧密,在实际场景使用时候,需要根据场景特点和业务逻辑来设计相应的预留,确认,撤销操作,相比MySQL XA,有一定的编程开发工作量
本质上TCC是一种设计模式,是一种理念,没有和任何技术耦合,不受限于任何技术,对所有有需求的技术方案都是适用的
最后TCC是交给业务代码之中编码实现的,所以 TCC可以跨数据库,跨业务,满足不同业务场景下的事务需求
而且,TCC的每一个操作对于数据库来说,都是一个本地数据库的事务,那么当操作结束的时候,本地数据库的事务就执行完成了,所以相关的数据库资源也就释放了,避免了数据层面的二阶段提交的长时间锁定资源,导致性能下降的问题
本章问题,就是通过TCC解决了指令执行的原子性,为什么呢?
在执行的过程中,TCC利用了二阶段提交的思想,既能够锁定成功,就相当于收到了锁定的确认操作,只有在所有的锁定确认收到了,才可以继续执行Confrim操作,在执行Confrim操作的时候,就不允许失败的存在,即使挂了,也会有后来人再上线的时候重新顶替上去