MVCC技术的核心思想如下:
当事务Ti执行一个读操作时,并发控制器对版本的获取依赖于事务Ti所能读取的数据的上下文。这个上下文(又称事务的快照,快照要和多版本相配合)是事务Ti在数据库系统里的当前并发执行的诸多事务状态的一份副本,通过其中的信息能够帮助判断获取到的元组对本事务是否是可读[6]。多版本并发控制技术不是一个可独立使用的事务并发控制技术,其需要基于其他并发控制技术来使用。如基于时间戳来使用,此时称为多版本时间戳排序机制(multiversion timestamp-ordering scheme);基于两阶段封锁协议来使用,此时称为多版本两阶段封锁协议(multiversion two-phase locking protocol)。下面我们分别讨论这两种并发控制技术。
1. 多版本时间戳排序机制
首先,数据库系统在事务开始前赋予事务一个时间戳,记为TS(Ti),这个时间戳决定了并发事务的调度顺序。其次,对于每个数据项X,多版本体现在:X有一个版本序列<X1,X2,…,Xn>,其中,每个版本Xi包括3个字段,分别如下。
Xi=value,value是数据项X的第i个版本的值,每个版本是由一个写操作生成的。W-timestamp(Xi)是创建Xi这个版本的事务的时间戳(不是当前时间戳值),即表明此数据项是被谁在什么时候创建的。
R-timestamp(Xi)是所有成功读取Xi这个版本的事务的时间戳。
再次,多版本时间戳排序机制通过如下规则可保证可串行性。事务Ti执行读操作或写操作,假设Xm是X满足如下条件的版本:其写时间戳是小于或等于TS(Ti)的最大写时间戳(确保了在所有版本中找到一个“最近版本”)。
如果事务Ti执行读操作Read(X)返回给事务Ti的值为Xm,则读永远不会被阻塞。如果事务Ti执行写操作Write(X),则需要分3种情况讨论:
如果同时满足TS(Ti)<R-timestamp(Xm),则中止事务Ti,这表明即将执行的这个写操作之后的时间上已经发生过一个读操作,如果允许写操作成功,则可能发生不可重复读异常现象。这是写读冲突,事务Ti被中止。注意,发生此种情况是因为事务Ti的写操作本来在物理时间上早于对Xm这个版本的其他事务的读操作,但是,因为并发执行是无序的,导致调度器进行TS(Ti)<R-timestamp(Xm)判断之前,R-timestamp(Xm)已经发生了。
如果同时满足TS(Ti)=W-timestamp(Xm),则系统更新事务Ti的Xm为新值,这表明本事务多次写过同一个数据项,新值覆盖旧值。如果同时满足TS(Ti)>W-timestamp(Xm),则系统为事务Ti的数据项X创建一个新值,这说明后发生的事务才创建新的版本。这是一种写写冲突,会导致产生新的版本。
2. 多版本两阶段封锁协议
首先,每个数据项X的多版本体现在:X有一个版本序列<X1, X2, …, Xn>,其中,每个版本Xi包括一个时间戳。在多数数据库中,这个时间戳对应的是唯一的一个名为事务号的事务标识。事务号通常是一个递增的数字。
其次,事务分为两种类型,一种是只读事务[7],另外一种是更新事务。这意味着需要事先知道事务的读写请求,进而告知事务管理器,事务管理器才能区分事务的类型并根据类型进行优化(多数多版本两阶段封锁协议的事务管理器都采取了一定措施为只读事务做优化)。只读事务开始获得事务号,并读取与该事务号对应的数据项的版本,只读事务在整个生命周期内只使用这个版本的数据。更新事务的操作可以细分为如下几种。
更新事务中的读操作,如果能获取该数据项的共享锁,则读取该数据项的最新版本的值。
更新事务中的写操作,如果能获得该数据项的排它锁,则为该数据项创建一个版本。刚创建的时候新版本的时间戳值为无穷大,致使其他并发事务不能读取到此尚未提交的数据项的版本。事务提交,此版本上的时间戳值加1,表示此后其他事务可以读写此版本的数据。如果不能获得排它锁,则表明有其他事务准备写或已经写了数据但没有结束,即锁没有被释放,本更新事务只能等待。
内容转自《分布式数据库原理、架构与实践》




