利用消息中间件实现分布式事务

一 事务的四个特性(ACID)

1 A(原子性)

原子性要求,事务是一个不可分割的执行单元,事务中的所有操作要么全都执行,要么全都不执行。

2 C(一致性)

一致性要求,事务在开始前和结束后,数据库的完整性约束没有被破坏。

3 I(隔离性)

事务的执行是相互独立的,它们不会相互干扰,一个事务不会看到另一个正在运行过程中的事务的数据。

4 D(持久性)

持久性要求,一个事务完成之后,事务的执行结果必须是持久化保存的。即使数据库发生崩溃,在数据库恢复后事务提交的结果仍然不会丢失。

二 事务的隔离级别

1 读未提交(Read uncommitted)

在该级别下一个事务在对一行数据进行修改的过程中,不允许另外一个事务对改行数据进行修改,但是允许读取该行数据。因此不会造成更新丢失,但会造成脏读和不可重复读。

2 读已提交(Read committed)

在该级别下一个事务在对一行数据进行修改的过程中,不允许另外一个事务对改行数据进行修改,同样也不允许读取该行数据。可以避免脏读。但是该级别下,一个事务在对一行数据进行读取的过程中,允许另一个事务访问该行数据(允许读写),因此会造成不可重复读现象。

3 可重复读(Repeatable read)

在该级别下一个事务在对一行数据进行修改的过程中,不允许另外一个事务对改行数据进行修改,同样也不允许读取该行数据。

在对一行数据进行读取的过程中,不允许其他事务对该行数据进行修改,允许对该行数据进行读取。可以避免不可重复读。

4 串行化(Serializable)

最高级别,该级别下一个事务在对一行数据进行读写操作时,不允许另外一个事务做任何操作。

三 分布式事务解决方案

目前的事务只支持单库事务,并不支持跨库事务。随着微服务日渐普及的今天,很多大型系统都是由若干个子系统组成的,每个子系统都拥有自己的数据库。有的业务场景涉及到多库之间的数据操作,这时候就会用到分布式事务。这里介绍的分布式事务解决方案是常用的2PC两段式,基于消息中间件的方案,结合下图进行说明。

利用消息中间件实现分布式事务_第1张图片

假设业务场景发生在系统A和B,要求A、B要么同时成功要么同时失败。

1 A系统开启事务前发送一条消息给消息中间件,消息中间件接收到消息后,对消息进行持久化处理,并把持久化结果反馈给系统A。

2 A系统收到持久化结果后,根据不同的结果做相应的处理。若是持久化成功,则A系统开始事务,同时消息中间件开始计时,并等待系统A事务处理结果。若是持久化失败,则系统A重新推送消息给消息中间件。

3 系统A开始事务后,把事务处理结果推送给消息中间件。若是一直收不到系统A的事务处理反馈,消息中间件会触发超时响应,并回查系统A的处理结果。

4 消息中间件根据系统A反馈的结果选择下一步的动作。

结果一:A系统事务成功提交     消息中间件看到系统A的事务已经成功提交会推送一条消息给系统B,让系统B可以开始自己的事务了。同时开始计时,等待系统B的事务处理结果。

结果二:A系统事务回滚     消息中间件看到系统A的事务失败了,进行了回滚,就知道没必要继续推送消息给系统B了,就会直接丢弃掉这条消息。

5 系统B收到消息中间件推送的消息后,开始自己的事务,并把事务处理结果反馈给消息中间件。若是没有收到系统B事务处理结果的反馈,会触发消息中间件的超时回查机制。

6 消息中间件根据系统B反馈的结果选择下一步的动作。

结果一:B系统事务成功提交     消息中间件看到系统B的事务已经成功提交,大家工作都完成了,该洗洗睡了,流程结束。

结果二:B系统事务回滚     消息中间件看到系统B的事务失败了,进行了回滚。这不是它想要的结果,因为系统A的事务已经成功提交了,系统B必须成功。于是会再发一条消息给系统B,让它重新开始自己的事务。若果连续好几次系统B的事务都失败了,这时候就需要人工干预了。

以上只是自己简单的理解,有什么不对的或是考虑不周到,欢迎讨论。

 

你可能感兴趣的:(事务)