ACID属性

详解ACID属性程序员

 

  计算机科学中ACID(Atomicity 原子性、Consistency 一致性、Isolation 隔离性、Durability 持久性)是一系列属性。sql

一、Atomicity 原子性数据库

  原子性要求每一个事物中的全部操做要么所有完成,要么就像所有没有发生同样:若是事物中的部分操做失败了,则整个事物事物失败了,结果就是数据库中的状态保持没变。原子性系统必须保证在各类状况下的原子性,包括主机断电、主机发生了错误、主机奔溃。对外界来讲,一个提交了的事物看起来(经过事物对数据库产生的影响)是不可分的,一个失败了的事物,对外界来讲就好像什么都没有发生过同样。并发

 

二、Consistency 一致性性能

  一致性确保了任何事物都会使数据库从一种合法的状态变为另外一种合法的状态。经过定义的各类规则,包括约束(constraints)、级联(cascades)、触发器(triggers)以及它们的组合来保证写入数据库的全部数据都必须是合法的。一致性并不能保证事物(程序)的正确性,换句话说事物的一致性并不必定如程序员所指望的那样(这应该是由应用层代码来负责的),它只能保证数据库中的全部数据都不会违反定义好的规则,无论程序有没有发生错误甚至是发生了任何错误都不会违反定义好的规则。spa

 

三、Isolation 隔离性操作系统

  隔离性保证了并发执行多个事物对系统的状态的影响和串行化执行多个事物对系统的状态的影响是同样的。隔离性是并发控制的主要目标。 经过并发控制的方法,一个未完成的事物的影响对其余事物是不可见的。日志

 

四、Durability 持久性code

  持久性保证了一个事物一旦被提交之后,其状态就保持不变,甚至是发生了主机断电、奔溃、错误等。例如,在关系数据库中,一旦一组 sql 语句被执行后,其结果就被永久保存(甚至事物刚被提交数据库系统就发生了奔溃)。为了主机抵御断电的风险,事物(或者是事物的结果)必须被记录在永久性存储中。事件

 

五、For Example

下面的例子进一步的说明了 ACID 属性。在下面的例子中数据库表有两列,A 和 B 。数据完整性约束要求 A 列的值和 B 列的值之和必须等于 100 。下面的 SQL 语句建立了一张表,这张表知足上面的约束条件——A+B=100 。

CREATE TABLE acidtest (A INTEGER, B INTEGER, CHECK (A + B = 100));

原子性的反例

在数据库系统中,原子性是 ACID 事物的四个属性之一。在一个原子事物中,一系列的数据库操做要么所有发生,要么所有不发生。这一系列的操做不能被相互分开,只执行部分操做。原子性要求这一系列操做不可分,原子性正如其名。原子性能够保证数据库不会出现部分更新的状况。部分更新的状况带来的问题远远要比全部的操做所有失败带来的问题还要严重。原子性意味着不可分。

一致性的反例

一致性是个很是泛化的术语,它要求数据必须知足全部的合法规则。之前面的例子为例,合法性规则是要求 A + B = 100 ,同时 A 和 B 还必须为整数。对于 A 和 B 来讲,其合法的范围是能够被推断出来的。全部的合法规则必须都被检查从而确保了事物的一致性。假设一个事物尝试着从 A 中减去 10 而不修改 B 。由于每一个事物结束之后都会进行一致性检查,在事物开始以前数据库就知道 A + B = 100 。若是事物成功的从 A 中减去 10 ,原子性就生效了。然而,有效性校验会发现 A + B = 90 ,这与数据库的约束规则不一致。整个事物必须被取消,被影响到的行回滚到执行事物以前的状态。若是还有其余约束、触发器、级联,每个独立改变的操做在事物被提交以前必须像前面同样进行一致性检查。

违反隔离性

为了演示隔离性,咱们假设两个事物在同时修改同一块数据。为了维护隔离性,其中一个事物必须等到另一个事物完成之后才能执行。考虑下面的两个事物, T1 从 A 中转出 10 到 B 。T2 从 B 中转出 10 到 A 。能够分析出共有四个操做: 
一、T1 从 A 中减去 10 。 
二、T1 给 B 中加上 10 。 
三、T2 从 B 中减去 10 。 
四、T2 给 A 中加上 10 。 
若是这些操做按照上面的顺序执行,就能够达到隔离性,尽管 T2 必须等待 T1 先执行。若是 T1 中途失败了,数据库系统会消除掉 T1 对数据库所产生的影响,T2 看到的仍然是合法的数据。

因为两个事物可能交错执行,这几个操做的实际执行顺序多是:

  • T1 从 A 中减去 10 。
  • T2 从 B 中减去 10 。
  • T2 给 A 增长 10 。
  • T1 给 B 增长 10 。

再次假设,T1 中途失败了,将会发生什么。若是 T1 在第四步:T1 给 B 增长 10 时失败了,而此时 T2 已经修改完了 A 和 B;被改变的数据没法恢复到 T1 执行以前的状态,致使了数据库产生了不合法的状态。 这就是有名的 “write-write failure” 失败,因为两个事物尝试同时修改同一个数据块。 在一个典型的系统中,这个问题能够解决。经过取消失败的事物 T1 ,从而使数据库恢复到上次的合法状态,而后从新开始执行被中断的事物 T2 。

违反持久性

假设一个事物从 A 中减去 10 加到 B 中。首先,事物会从 A 中减去 10 ,而后再在 B 中加上 10 。 在此时,执行事物的程序会告诉用户,事物已经成功执行了。而后,此时这些改变的数据仍然还在磁盘缓冲区中排队等待写入磁盘中。若是这时主机发生断电,数据库中全部的改变就会丢失。用户还觉得全部的改变都已经持久化到磁盘中了。

实现

处理一个事物一般须要一系列的操做,任意一个操做失败了都会致使整个事物的失败,所以,形成事物失败的缘由有好多个。例如,系统的磁盘已经满了,再没有空间了,或者是事物已经用光了操做系统分配给它的 CPU 时间片。有两种你们都很熟悉的流行技术:预写式日志记录和影子分页。这两种技术中,必需要在将被更新的全部信息上获取锁。获取的锁依赖事物的隔离级别,有可能全部的数据仅仅是被读取,也须要获取锁。在预写式日志记录技术中,在改变数据库以前经过复制原始的(未改变的)数据到日志记录中来保证原子性。有了日志记录就可使数据库恢复到发生奔溃事件以前的一致性状态。在影子分页技术中,更新被应用到数据库的部分拷贝中,当数据库事物提交时,新的拷贝才被激活了。

好多数据库依赖锁来实现 ACID 能力。锁意味着事物在其须要访问的数据上打个标记,这样一来数据库管理系统就会知道这些数据在该事物完成(事物成功或失败)以前不容许其余事物修改这些被打了标记的数据。锁在数据被处理以前必须获取到,也包括处理那些只会被读取但不会被修改的数据以前也要获取锁。非日常事物一般须要大量锁,致使了不小的性能开销同时也阻塞了其余事物。例如,用户 A 正在执行一个事物,须要读取某一行数据而这时另一个用户 B 正在修改这一行数据。用户 B 必须等到用户 A 的事物完全完成。一般能够经过两个阶段锁来保证全隔离性。

相关文章
相关标签/搜索