1.3 ACID
已故的Jim Gray [2]在20世纪70年代才真正发明了现代事务处理,并在1981年6月写入经典论文“事务概念:优点和限制”(The Transaction Concept: Virtues and Limitations)。从这篇论文开始,有了ACID(原子性、一致性、隔离性和持久性)这个缩写词。Gray的论文论述了原子性、一致性、持久性,隔离性是后来补充的。Bruce Lindsay和他的同事于1979年在Gray的论文的基础上写了论文“分布式数据库要点”(Notes on Distributed Databases),并制定了一致性的基本原理和数据库复制的首要标准。1983年,Andreas Reute和Theo Härder发表了论文“面向事务的数据库恢复的原则”(Principles of Transaction-Oriented Database Recovery),并创造了ACID这个名词。
ACID这个术语的具体含义如下。
原子性。事务中的任务(或所有任务)要么全部执行,要么全不执行。这是或全或无的原则。如果事务中的一个元素失败,则整个事务失败。SQL坚守这一原则,INSERT语句会将整个数据集插入表中,DELETE语句会从表中删除整个一组行,UPDATE语句会删除并插入整个数据集。
一致性。事务必须在任何时候都满足系统定义的所有协议和规则。事务不能违反这些协议,同时数据库在事务开始和结束时必须保持在一致状态。在SQL中,这意味着在事务结束时所有的约束是TRUE。这可能是由于系统的新状态是有效的,或者是由于该系统回滚到其初始的一致状态。
隔离性。事务无法访问处于中间状态或未完成状态的任何其他事务的数据。因此,每一个事务自身都是独立的。在数据库中,性能和事务的一致性是必需的。但在SQL中不是这样,只有隔离级别的概念。会话可以在某些隔离级别看到未提交的数据。这个未提交的数据可以通过会话回滚,所以从某种意义上说,这些数据根本不存在。
持久性。一旦事务完成,它将是完整、持续的,并且不能被撤销。即便是在系统故障、断电或是其他类型的系统宕机的情况下数据也能存活。这是一个硬件问题,但是我们仍然在这方面做了很好的工作。当然,我们只是不要让数据在易失性存储器中存储,而是尽快将其持久化。
这项功能(特性)在大多数SQL数据库中是通过各种“加锁”的方案来实现的。“锁”会决定其他会话如何使用资源,如只读取提交的行,或者允许读未提交的行,等等。这就是所谓的悲观并发模型(pessimistic concurrency)。其基本假设是,你必须保护自己免受其他人的影响,并且冲突是常态。
另一种流行的并发模型称为乐观并发(optimistic concurrency)。如果你了解过数字影片行业,你就能理解这种模式。每个人都会得到数据的一个副本,然后按照他们希望的那样进行处理。在缩微胶片系统中,影片管理员制作电影文档(影片)的副本,并把它们分发出去。每位员工将修改他自己的副本,并把它(修改后的影片、文档)提交到文档纪录中心。
这种模型中假设:
查询比数据库变更常见得多,专为查询设计;
数据库变更过程中冲突极少发生,将其当作例外;
如果确实遇到冲突,相关的会话可以选择回滚,或者可以设置解决的规则。等待情况恢复正常,避免恐慌。
对于缩微胶片系统,大多数请求是读取信息,数据从来没有修改过。对内容进行修改的请求通常在时间上是分离的,所以它们不会产生冲突。当一名或多名员工做了同样的修改时,并不会产生冲突,修改会直接生效。当两个员工的修改有冲突时,影片经理会两个修改都拒绝,然后他等待通过应用规则或是稍后再做的新修改。
乐观并发取决于每一行的时间戳,保持历史副本。用户可以在一个自己知道出局苦处于某个ACID状态的时间点来查询数据库。用微缩胶片的比喻来说,就像中央记录员在等待他人返回其标记(修改)的副本时的处理方式一样。但是,这也意味着,我们在“时间=t0”时开始与该数据库交互,并且如我们所希望的那样,在“时间=t0, t1, t2,…, tn”时,基于所述时间戳同样能看到对应的数据。由于“锁”的作用,插入、删除和更新不会影响查询。如果要对一个恒定的流入数据进行查询,如股票和商品交易,乐观并发非常有用。
关于乐观并发的更详细信息将在关于流式数据库的5.1.1节中讨论。这种方法是最适于处理不断变化的数据,但又必须保持数据完整性,并在某个时间点呈现的数据一致视图的数据库。
需要关注的是:数据的集中管理方式并没有改变!