ACID(Atomicity 原子性、Consistency 一致性、Isolation 隔离性、Durability 持久性)是一系列属性。
这些属性保证了数据库事物的可靠。在数据库中,对数据的一系列操作在逻辑上可以看成一个整体的操作,这个整体的操作就叫事物。
Atomicity(原子性)
原子性要求每个事物中的所有操作要么全部完成,要么就像全部没有发生一样:如果事物中的部分操作失败了,则整个事物事物失败了,结果就是数据库中的状态保持没变。原子性系统必须保证在各种情况下的原子性,包括主机断电、主机发生了错误、主机奔溃。对外界来说,一个提交了的事物看起来(通过事物对数据库产生的影响)是不可分的,一个失败了的事物,对外界来说就好像什么都没有发生过一样。
Consistency(一致性)
一致性确保了任何事物都会使数据库从一种合法的状态变为另一种合法的状态。通过定义的各种规则,包括约束(constraints)、级联(cascades)、触发器(triggers)以及它们的组合来保证写入数据库的所有数据都必须是合法的。一致性并不能保证事物(程序)的正确性,换句话说事物的一致性并不一定如程序员所期望的那样(这应该是由应用层代码来负责的),它只能保证数据库中的所有数据都不会违反定义好的规则,不管程序有没有发生错误甚至是发生了任何错误都不会违反定义好的规则。
Isolation(隔离性)
隔离性保证了并发执行多个事物对系统的状态的影响和串行化执行多个事物对系统的状态的影响是一样的。隔离性是并发控制的主要目标。 通过并发控制的方法,一个未完成的事物的影响对其他事物是不可见的。
Durability(持久性)
持久性保证了一个事物一旦被提交以后,其状态就保持不变,甚至是发生了主机断电、奔溃、错误等。例如,在关系数据库中,一旦一组 sql 语句被执行后,其结果就被永久保存(甚至事物刚被提交数据库系统就发生了奔溃)。为了主机抵御断电的风险,事物(或者是事物的结果)必须被记录在永久性存储中。
实现
处理一个事物通常需要一系列的操作,任意一个操作失败了都会导致整个事物的失败,因此,造成事物失败的原因有好多个。例如,系统的磁盘已经满了,再没有空间了,或者是事物已经用光了操作系统分配给它的 CPU 时间片。有两种大家都很熟悉的流行技术:预写式日志记录和影子分页。这两种技术中,必须要在将被更新的所有信息上获取锁。获取的锁依赖事物的隔离级别,有可能所有的数据仅仅是被读取,也需要获取锁。在预写式日志记录技术中,在改变数据库之前通过复制原始的(未改变的)数据到日志记录中来保证原子性。有了日志记录就可以使数据库恢复到发生奔溃事件之前的一致性状态。在影子分页技术中,更新被应用到数据库的部分拷贝中,当数据库事物提交时,新的拷贝才被激活了。
锁
好多数据库依赖锁来实现 ACID 能力。锁意味着事物在其需要访问的数据上打个标记,这样一来数据库管理系统就会知道这些数据在该事物完成(事物成功或失败)之前不允许其他事物修改这些被打了标记的数据。锁在数据被处理之前必须获取到,也包括处理那些只会被读取但不会被修改的数据之前也要获取锁。非平常事物通常需要大量锁,导致了不小的性能开销同时也阻塞了其他事物。例如,用户 A 正在执行一个事物,需要读取某一行数据而这时另外一个用户 B 正在修改这一行数据。用户 B 必须等到用户 A 的事物彻底完成。通常可以通过两个阶段锁来保证全隔离性。