学成总结(分布式事务)

什么是分布式事务?

在单体应用中只有一个系统并且操作一个数据库,事务为本地事务,数据库本身就支持了对本地事务回滚的解决方案。

在分布式系统中有这2个情况可能会产生分布式事务:

  1. 多个系统分别有自己的数据库

    比如订单系统有自己的订单数据库,库存系统有自己的库存数据库
    当在订单系统中在订单表增加了一条数据之后,如果调用库存系统减库存的时候发生错误,这时候订单系统回 滚是没有用的,因为这是2个系统并且是对2个不同数据库的连接,完全不相关,这时就产生了分布式事务难题。
    学成总结(分布式事务)

  2. 多个系统共用一个数据库
    如果订单系统和库存系统共用一个数据库,因为是2个系统,会产生2个连接,此时单个系统回滚只会回滚当 前连接发生的操作,也会产生分布式难题
    学成总结(分布式事务)

还有一种情况也会产生分布式事务:
在一个系统中用到了多个数据库也可能会产生分布式事务,因为数据库只能回滚自己相关的操作

针对于分布式事务的解决方案有以下几种:

1. 两阶段提交协议

该方案主要针对于在一个系统中连接多个数据库的情况。
为什么叫两阶段提交协议?因为分为2个阶段
第一个阶段:准备

  1. 系统连接上2个数据源
  2. 系统通过事务管理器 向两个库发起prepare,两个数据库收到消息分别执行本地事务(记录日志),但不提 交,如果执行成功则回复yes,否则回复no

第二个阶段:提交或者回滚

  1. 事务协调器收到回复,只要有一方回复no则分别向参与者发起回滚事务,参与者开始回滚事务。
  2. 事务协调器收到回复,全部回复yes,此时向参与者发起提交事务。如果参与者有一方提交事务失败则由事务协 调器发起回滚事务。
    图示:
    学成总结(分布式事务)
    Spring + JTA Atomikos 可以实现 demo如下
    https://github.com/zdx818/itmayiedu_days29_springboot_mybatis03

TCC事务补偿

1、Try
下单业务由订单服务和库存服务协同完成,在try阶段订单服务和库存服务完成检查和预留资源。
订单服务检查当前是否满足提交订单的条件(比如:当前存在未完成订单的不允许提交新订单)。
库存服务检查当前是否有充足的库存,并锁定资源。
2、Confirm 订单服务和库存服务成功完成Try后开始正式执行资源操作。
订单服务向订单写一条订单信息。
库存服务减去库存。
3、Cancel
如果订单服务和库存服务有一方出现失败则全部取消操作。
订单服务需要删除新增的订单信息。
库存服务将减去的库存再还原。

优点:最终保证数据的一致性,在业务层实现事务控制,灵活性好。
缺点:开发成本高,每个事务操作每个参与者都需要实现try/confirm/cancel三个接口。

注意:TCC的try/confirm/cancel接口都要实现幂等性,在为在try、confirm、cancel失败后要不断重试。
什么是幂等性?

幂等性是指同一个操作无论请求多少次,其结果都相同。
幂等操作实现方式有:
1、操作之前在业务方法进行判断如果执行过了就不再执行。
2、缓存所有请求和处理的结果,已经处理的请求则直接返回结果。
北京市昌平区建材城西路金燕龙办公楼一层 电话:400-618-9090
3、在数据库表中加一个状态字段(未处理,已处理),数据操作时判断未处理时再处理。

本地消息表

直接使用消息队列

这个的意思,就是干脆不要用本地的消息表了,直接基于 MQ 来实现事务。比如阿里的 RocketMQ 就支持消息事务。

本项目使用的是本地消息表的方式解决了分布式事务的问题
学成总结(分布式事务)
这个方案说实话最大的问题就在于严重依赖于数据库的消息表来管理事务啥的,如果是高并发场景咋办呢?咋扩展呢?所以一般确实很少用。