1. 本地事务:
本地事务就是传统的数据库事务,它的执行模式很简单:
(1)创建事务
(2)进行数据库操作
(3)提交事务/出错回滚
同时,它有这么几个特征
(1)一次事务只连接一个支持事务的数据库(一般来说都是关系型数据库)
(2)事务的执行结果保证ACID
(3)会用到数据库锁
提到了ACID,参考WIKI上的解释:https://zh.wikipedia.org/wiki/ACID 、
Atomicity 原子性:all or nothing,要么都被修改,要么保持原有状态。
indivisible,不可分割,一个事务就是一个最小的无法分割的独立单元,不允许部分成功部分失败。
Consistency 一致性:一致性要求任何写到数据库的数据都必须满足于预先定义的规则(比如余额不能小于0、外键约束等)。
Isolation 隔离性:隔离性要求如果两个事务修改同一个数据,则必须按顺序执行,并且前一个事务如果未完成,那么未完成的中间状态对另一个事务不可见。
Durability 持久性:持久性的关键在于一旦“完成提交”(committed),那么数据就不会丢失
2.分布式事务
随着软件的复杂度提升,我们会需要一种可以在多个数据库之间完成事务(分布式事务)的方法,而这个方法也必须能够保证ACID。
于是就出现了2PC,Base,TCC模式。
(1)2PC:分为协调者,参与者。
其执行过程如下:
Commit request phase /Voting phase阶段:
协调者发送一个查询是否同意commit的请求到所有参与者,并且等待所有参与者给出应答。
参与者收到请求,开始执行事务,执行到就差commit为止(不commit)。每个参与者根据操作结果返回Yes或No
Commit phase / Completion phase阶段:
成功:所有参与者应答Yes
调者发送commit指令到所有参与者,每个参与者执行commit,并发送ack到协调者。当协调者收到每个参与者的ack之后则事务完成。
失败:任意参与者应答No,或者在commit request阶段超时。
协调者发送rollback指令到所有参与者,每个参与者执行rollback,并发送ack到协调者,当协调者收到每个参与者的ack之后则事务撤销。
可能会出现的问题:
a. 协调者不宕机,参与者宕机;
b. 协调者宕机,参与者不宕机;
c. 协调者宕机,参与者也宕机;
对于a,当在事务进行过程中,有参与者宕机时,他重启以后,可以通过询问其他参与者或者协调者,从而知道这个事务到底提交了没有。
对于b,协调者宕机后,可以起新的协调者,然后查询所有参与者的状态是否有 commit 的,如果有,则继续 commit,如果都没有,则 abort。
对于c,是唯一 2PC 不能解决的:当协调者在发出 commit 消息后宕机了,而唯一收到这条命令的一个参与者也宕机了,这个时候这个事务就处于一个未知的状态,没有人知道这个事务到底是提交了还是未提交,从而需要数据库管理员的介入,防止数据库进入一个不一致的状态。当然,如果有一个前提是:所有节点或者网络的异常最终都会恢复,那么这个问题就不存在了,协调者和参与者最终会重启,其他节点也最终也会收到commit T的信息。
2PC缺点:
性能低下,2PC协议是阻塞式的。当协调的数据库越来越多时,性能无法接受。
无法水平扩展以提升性能,只能靠垂直扩展(提升硬件)——更快的CPU、更快更大的硬盘、更大更快的内存——但是这样很贵,并且很容易遇到极限。
(2)Base模式
BASE和ACID相反,ACID是悲观的,它要求所有操作都必须保证一致性,而BASE是乐观的,它接受数据库的一致性在不断变化当中。同时,BASE对于CAP中的C做出了一定的妥协——接受临时的不一致,采用最终一致性。
其对于ACID的保证如下:
ACID - A,不保证,一旦开始“写”则不可能回滚。
ACID - C,保证最终一致性。
ACID - I,不保证,是因为一个大事务是由多个小事务组成,每个小事务都会独立提交。
ACID - D,保证,因为数据库保证D。
CAP - C,保证最终一致性。
CAP - A,保证基本可用。
CAP - P,保证。
参考博文:https://segmentfault.com/a/1190000013775137