ACID

      在计算机科学中,ACID(原子性、一致性、隔离性、持久性)是数据库事务的一组属性,目的是在发生错误、断电等情况下保证有效性。在数据库上下文中,满足ACID属性的数据库操作序列(可以将其视为数据上的单个逻辑操作)称为事务。例如,从一个银行账户到另一个银行账户的资金转移,即使涉及多个变化,如借记一个账户和贷记另一个账户,也是一笔交易。1983年,Andreas Reuter和Theo Harder在Jim Gray的早期工作的基础上创造了首字母缩略词ACID,作为原子性、一致性、隔离性和持久性的缩写。这四个属性描述了事务范型的主要保证,它影响了数据库系统开发的许多方面。根据Gray和Reuter的说法,IMS早在1973年就支持ACID事务(尽管后来出现了ACID这个术语)。

Characteristics(特性)

Reuter和Harder定义的这四种属性的特征如下:

Atomicity:

事务通常由多条语句组成。原子性保证将每个事务视为一个单独的“单元”,这个单元要么完全成功,要么完全失败:如果组成事务的任何语句没有完成,整个事务就会失败,数据库也不会改变。原子系统必须保证在每种情况下的原子性,包括电源故障、错误和崩溃。原子性的保证可以防止对数据库的更新只发生部分,这比完全拒绝整个系列操作请求可能会导致更大的问题。因此,其他数据库客户端无法观察到事务正在进行中。在某个时刻,它还没有发生,而在下一个时刻,它已经全部发生了(或者如果正在进行的事务被取消,则什么也没有发生)。原子事务的一个例子是一个货币从银行a账户转移到b账户。它包含两个操作,从a账户中取出钱和把钱增加到b储蓄账户,执行这些操作在一个原子事务确保数据库仍然处于一致状态,也就是说,钱既不失去也不增加如果这两个操作失败。

Consistency:

一致性确保事务只能将数据库从一种有效状态带到另一种有效状态,维护数据库不变性:写入数据库的任何数据必须根据所有定义的规则(包括约束、级联、触发器以及它们的任何组合)有效。这可以防止非法事务破坏数据库,但不能保证事务是正确的。引用完整性保证了主键-外键关系。

Isolation:


事务通常是并发执行的(例如,多个事务同时读写一个表)。隔离确保事务的并发执行使数据库处于与顺序执行事务时相同的状态。隔离是并发控制的主要目标;根据使用的方法,不完整事务的影响甚至可能对其他事务不可见。

Durability:

持久性保证了一旦提交了事务,即使在系统故障(例如,断电或崩溃)的情况下,它也将保持提交状态。这通常意味着完成的事务(或它们的影响)被记录在非易失性内存中如磁盘。


下面是例子:
下面的例子进一步说明了ACID的特性。在这些示例中,数据库表有A和B两列。完整性约束要求A中的值和B中的值之和必须为100。下面的SQL代码按照上面的描述创建一个表:

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

Atomicity

原子性是保证原子事务中的一系列数据库操作要么全部发生(一个成功的操作),要么一个也不发生(一个不成功的操作)。这一系列的操作不能被分开,只能执行其中的一部分,这使得这一系列的操作“不可分割”。原子性的保证可以防止对数据库的更新只发生部分,这比完全拒绝整个系列请求操作可能会导致更大的问题。换句话说,原子性意味着不可分割性和不可约性。或者,我们可以说一个逻辑事务可以由一个或多个(几个)物理事务组成。除非并且直到所有的组件物理事务都被执行,否则逻辑事务不会在数据库的影响下发生。假设我们的逻辑事务由资金由账户a转移到账户b,这逻辑事务可能由几个物理事务组成的第一个删除账户的金额作为第一物理事务,然后作为第二事务,将上述钱存入账户b。我们不希望看到从账户a删除之前它已转入帐户b,然后,除非并且直到两个交易都发生了,并且金额已经转移到账户B,否则转移不会影响数据库。

Consistency failure:

一致性是一个非常普遍的术语,它要求数据必须满足所有验证规则。在前面的示例中,验证要求a + B = 100。必须检查所有验证规则以确保一致性。假设一个事务试图在不改变B的情况下从a中减去10,因为每个事务之后都会检查一致性,所以在事务开始之前a + B = 100。如果事务成功地从A中删除10,就会实现原子性。但是,验证检查将显示a + B = 90,这与数据库的规则不一致。整个事务必须取消,受影响的行必须回滚到它们的事务前状态。如果存在其他约束、触发器或级联,则在提交事务之前,将以与上述相同的方式检查每个更改操作。其他约束也可能出现类似的问题。我们可能要求A和B的数据类型都是整数。如果我们输入,比如说,A的值13.5,那么该事务将被取消,或者系统可能会以触发器的形式发出警报(如果/当触发器被写入该效果时)。另一个例子是完整性约束,它不允许我们删除一个表中的行,该表中的主键至少被其他表中的一个外键引用。

Isolation failure:

为了演示隔离,我们假设两个事务同时执行,每个事务都试图修改相同的数据。其中一个必须等到另一个完成才能保持隔离。考虑两个事务:T1转移10从A到B, T2转移20从B到A .
组合有四个动作:
1、T1从A减去10。
2、T1给B添加10 。
3、T2从B 减去20
4、T2给 A增加了20 .
如果按顺序执行这些操作,保持隔离,尽管T2必须等待。考虑一下如果T1中途失效会发生什么。数据库消除了T1的影响,T2只看到有效的数据。
通过交错事务,操作的实际顺序可能是:
1、T1从a中减去10,
2、T2从B中减去20。
3、T1失效时,
4、T2已经修改了A;
如果不留下一个无效的数据库,它就不能恢复到T1之前的值。这被称为写-写失败,因为两个事务试图写入相同的数据字段。在典型的系统中,可以通过恢复到最后一个已知的良好状态、取消失败的事务T1和从良好状态重新启动中断的事务T2来解决这个问题。

Durability failure:

考虑一个从a向b传输10的事务。首先,它从a中删除10,然后向b添加10。此时,用户被告知事务成功了。但是,更改仍然在磁盘缓冲区中排队,等待提交到磁盘。此时电源失效,更改丢失。用户假定(可以理解地)更改已经完成,事实上并没有更新。

Implementation:

处理事务通常需要一系列操作,这些操作由于多种原因可能会失败。例如,系统的磁盘驱动器可能已经没有空间了,或者已经耗尽了分配的CPU时间。有两种流行的技术:提前写日志 write-ahead logging和影子分页shadow paging(在计算机科学中,影子分页是一种在数据库系统中提供原子性和持久性的技术。这里的页面指的是物理存储单元,通常为1到64 KiB)。在这两种情况下,必须获取要更新的所有信息上的锁,并根据隔离级别,可能还需要读取所有数据。在写前日志中,原子性是通过在更改数据库之前将原始(未更改的)数据复制到日志中来保证的。它允许数据库在崩溃时返回一致的状态。在影子分页中,更新应用于数据库的部分副本,并在事务提交时激活新副本。

Locking vs multiversioning:
 

      许多数据库依赖于锁定来提供ACID功能。锁定意味着事务标记它访问的数据,以便DBMS知道在第一个事务成功或失败之前不允许其他事务修改它。在处理数据(包括读取但未修改的数据)之前,必须始终获取锁。复杂的事务通常需要大量的锁,从而导致大量的开销,并阻塞其他事务。例如,如果用户A正在运行一个事务,该事务必须读取用户B想要修改的一行数据,那么用户B必须等待,直到用户A的事务完成。通常采用两阶段锁来保证完全隔离。
      锁定的一种替代方法是多版本并发控制,其中数据库为每个读取事务提供另一个活动事务正在修改的数据的先前的、未修改的版本。这允许读取器在不获取锁的情况下进行操作。写事务不会阻塞读事务,读也不会阻塞写。回到这个示例,当用户A的事务请求用户B正在修改的数据时,数据库向A提供了用户B开始事务时存在的数据版本。即使其他用户正在更改数据,用户A也可以获得数据库的一致视图。一个实现,即快照隔离,放松了隔离属性。

Distributed transactions:

保证跨分布式数据库的分布式事务中的ACID属性(其中没有一个节点负责影响事务的所有数据)会带来额外的复杂性。网络连接可能失败,或者一个节点可能成功完成其事务的一部分,然后由于另一个节点的失败而需要回滚其更改。两阶段提交协议(不要与两阶段锁定混淆)为分布式事务提供原子性,以确保事务中的每个参与者都同意是否应该提交事务。简单地说,在第一阶段,一个节点(协调器)询问其他节点(参与者),只有当所有节点都回答准备就绪时,协调器才会在第二阶段将事务形式化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值