ACID
概念
在传统数据库系统中,事务具有ACID四个属性(Jim Gray在《事务处理:概念与技术》中对事务进行了详尽的讨论)。
- 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
- 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。
- 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境中执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
- 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
分析
ACID四个特性虽然并列表述,但是四个特性并不是同等级的。
一致性C,才是数据的最终约束、最终目的。原子性A、隔离性I和持久性D都是实现一致性C的工具。
没有原子性,一致性肯定无从不保证。但是只有原子性,也是无法保证一致性的。 假设一笔转账从A账户转到B账户100元,这个操作包括:读取A,A-100,写回A,读取B,B+100,写回B。 如果同时只有一个事务,看起来原子性可以保证一致性。
但是如果同时有另外一个事务发生,从B账户转到A账户200元,这个操作包括:读取B,B-200,写回B,读取A,A+200,写回A。
如果两个事务不做任何隔离,就算两个事务都保证了原子性,也无从保证一致性。读者可以自行分析有多少种结果出现。
所以,当多个事务同时发生时,要保证一致性,就要增加另外一个特性:隔离性。隔离性就是为了保证多个事务同时发生时的一致性的。
隔离有不同的级别:
- Read Uncommitted:事务T1可以读取事务T2已经部分修改,但是尚未提交的数据。这样会出现读脏数据问题(Read Dirty),就是读取别人修改了一半的数据。为了解决这个问题,提升事务隔离等级,规定事务T1只能读取事务T2已经提交的数据。
- Read Committed:规定事务T1只能读取事务T2已经提交的数据。这样确实不会再出现读脏数据问题(Read Dirty),但是一致性是否完全得到保证了呢?没有。举个例子:事务T1在执行的时候,读取A=100,此时事务T2将A=200,并提交了事务,然后事务T1再读取A,因为事务T2已经提交,所以T2对A的修改,应该反映到事务T1种,此时发现A=200,对于事务T1来说,出现了数据A不可重复读的问题(Unrepeatable Read)。 为了解决这个问题,再次提升事务隔离等级,规定事务T1只能读取T1开始前已经提交的事务。
- Read Repeatable:如果事务T2在事务T1开始前,还没有提交,那T2在T1过程种提交事务,T2的操作A=200,在事务T1是看不到的。这样就解决了不可重复读(Unrepeatable Read)的问题。那这个是否就完全保证一致性了呢。没有。
还出现换幻读问题。比如事务T1将表中100条数据A=100,修改为A=200。此时事务T2在表中增加了一条数据A=100。然后事务T1发现数据总量为101条,100条A=200,一条A=100。这就是幻读问题。事务T1针对的是100条数据,事务T2针对的是1条数据,所以两个事务本来是不相关的。要解决这个问题,要进一步提高隔离等级。
- Seriablable:事务序列化。序列化是最高等级的,但是也是效率最低的。