解读事务的ACID!

事务的ACID特性大学数据库课程基本都学过,但是学完也就大概知道是干嘛的,后来也没仔细想这个东西了,后来接触了NoSQL系统的一致性,于是重新学习 ACID,发现还有很多误区。今天来理一理。

本文预计阅读时间 7 分钟。

事务

事务是什么?

wiki:A transaction symbolizes a unit of work performed within a database management system (or similar system) against a database, and treated in a coherent and reliable way independent of other transactions.

数据库系统概念:构成单一逻辑工作单元的操作集合称作事务。

简单来说,事务就是包含一些性质一系列操作。下面我们分别介绍这两点。

一系列操作

事务的英文是 Transaction,交易。这个就是金融里的交易,交易的基本动作就是转账,一个最经典的事务就是 A 给 B 转 50 元。这个事务由数据库执行就是6行代码:

begin transaction(事务开始标志)

read(A)

A = A - 50

write(A)

read(B)

B = B + 50

write(B)

end transaction(事务结束标志)

其中 read 为将变量从磁盘读到内存,+、- 操作为内存操作,write 为将内存中的值写入磁盘。

在事务开始和结束标志中间就是一系列操作。其实就是一段代码而已,没有任何特别的,那么为什么要提出事务的概念呢?那就要说到事务的性质了。

原子性(Atomicity)

原子性:事务中包含的各项操作要么全部执行,要么全部不执行。

为什么有这个性质?对于转账操作而言,普通用户认为这就是一个动作,这个动作要么发生,要么不发生,不应该出现发生了一半的情况:即 A 的账户少了 50,但 B 的账户没有多 50。因此,原子性是指将事务的一系列代码当做一行代码来执行。

那假如执行一半停电了怎么办?数据库重启后需要恢复到没执行事务的状态,即回滚。

一致性(Consistency)

一致性:隔离执行事务时(没有并发时),保持数据库的一致性。

这个解释是不是很流氓。

看看wiki的:Consistency ensures that a transaction can only bring the database from one valid state to another, maintaining database invariants: any data written to the database must be valid according to all defined rules, including constraints, cascades, triggers, and any combination thereof. This prevents database corruption by an illegal transaction, but does not guarantee that a transaction is correct.

一致性就是数据库里的数据满足数据库的所有定义的约束,这里的约束包括对主键和外键的数据库内部约束,也包括人为定义的对两个值的约束,如 A+B=10 或者高中毕业年份必须比入学年份大3。编写出符合一致性的事务是事务程序员的任务,而数据库会做最终检查,不符合一致性的事务会被数据库拒绝。

白话一点:数据库中有自己的规则,这些规则用来保证数据库的状态是正常的(一致的),事务要来执行就需要遵守数据库的规则。

隔离性(Isolation)

隔离性:事务的隔离性是指在并发执行中,系统保证,对于两个事务T1,T2。在T1看来,T1或者在T2开始前完成,或者在T2完成后开始。让事务感受不到系统中有其他事务在并发执行。

隔离性与调度有关,调度就是代码的执行顺序。考虑一个动作是 A 给 B 转 50,另一个动作是 B 给 A 转 50。这两个动作都是由 6 行代码组成。

在保证事务内部代码执行顺序不变的前提下,数据库可以有很多种调度策略来执行这 12 行代码。最严格也最安全的是串行调度,即一次执行一个事务,n 个事务的串行化调度策略有 n! 种,就是个排列。下面是 2 个事务的 2 种串行调度。

需要明确,不同的串行调度策略结果可能不一样,但都能满足一致性。想想为啥?因为每一个事务都满足一致性啊,一个一个执行肯定也满足了,不管什么顺序。

除了串行调度,还有很多其他调度,但是符合要求的调度应该都可以等价为一个串行调度,这种符合要求的调度就是可串行化调度。考虑下边 2 个调度:

左边的调度就是可串行化调度,右边的调度就是不可串行化调度。

可串行化是一种隔离级别。为了满足性能的要求,数据库还提供了其他隔离级别,这些隔离级别按由强到弱分别为:

可串行化 > 可重复读 > 读已提交 > 读未提交

不同的隔离级别对数据库使用者的表现不一样。将事务按照一定的隔离级别隔离是并发控制的主要目标。

持久性(Durability)

持久性:事务一旦提交(commit),对数据库中对应数据的状态变更就应该是永久性的。

事务的提交类似 word 的保存,保存后就不会丢失了,避免 word 崩了心态炸了。

简单来说就是事务对数据的操作应该写磁盘,不能仅仅停留在内存中。

四种性质的交叉

原子性和一致性的关系比较不好理解。

原子性是一致性的必要条件吗?不是,假如数据库的约束为 A 和 B 都大于0。

begin transaction

write(A)=50

write(B)=50

end transaction

当执行完write(A)后,不执行write(B),这里不符合原子性,但是满足一致性。

原子性是一致性的充分条件吗?不是,同上的约束,A 和 B 都大于 0,考虑下边这个事务

begin transaction

write(A)=-10

write(B)=-20

end transaction

这里即使满足原子性,将 A 和 B 的值都改掉,也不满足一致性。

隔离性和一致性的关系简单一点。隔离性是事务并发时保证一致性的必要条件。

原子性、隔离性、持久性是数据库需要为所有事务提供的通用处理方式。唯有一致性是和业务挂钩的。他们的关系大概如上图。这样,事务的基本定义和性质就清楚了。

今天东哥总结

事务是包含若干个数据库操作的代码。一致性和原子性要求事务具有回滚能力,隔离性对并发控制提出了要求。持久性更像是一个数据库的特性。 原子性、隔离性、持久性对编程人员是透明的,而一致性的要求编程人员写出的事务是符合一致性的(否则数据库将拒绝该事务)。

致谢:东哥!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180831G11BFT00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券