数据库系统概念 第十五章 并发控制

基于锁的协议

  锁:

    共享锁:可读不可写

    排他锁:可读又可写

    我们将要求在系统中的每一个事务遵从称为封锁协议的一组规则,这些规则规定事务何时对数据项们进行加锁、解锁

  锁的授予:

    当事务i申请对数据项Q加M型锁时,并发控制管理器授权加锁的条件是:

      1 不存在在数据项Q上持有与M型锁冲突的锁的其他事务

      2 不存在等待对数据项Q加锁且先于i申请加锁的事务

  两阶段封锁协议:

    保证可串行性的一个协议是两阶段封锁协议。该协议要求每个事务分两个阶段提出加锁和解锁申请:

      1 增长阶段:事务可以获得锁,但不能释放锁

      2 缩减阶段:事务可以释放锁,但不能获得新锁

    最初事务处于增长阶段,事务根据需要获得锁,一旦该事务释放了锁,它就进入了缩减阶段,并且不能再发出加锁请求。

    两阶段封锁并不保证不会发生死锁。

    严格两阶段封锁协议:除了要求封锁是两阶段之外,还要求事务持有的所有排他锁必须在事务提交后方可释放。

    强两阶段封锁协议:要求事务提交之前不得释放任何锁。

    锁转换:将共享锁升级为排他锁,将排他锁降级为共享锁

    严格两阶段封锁与强两阶段封锁(含锁转换),在商用数据库系统中广泛使用

    这里介绍一种简单却广泛使用的机制,它基于来自事务的读、写请求,自动地为事务产生适当的加锁、解锁指令:

      1 当事务进行read操作时,系统就产生一条lock-s指令,该read指令紧跟其后

      2 当事务进行write操作时,系统检查事务是否已在数据项上持有共享锁,若有,系统发现upgrade指令,后接write指令,

        否则,系统发出lock-x指令,后接write指令

      3 当一个事务提交或中止后,该事务持有的所有锁都被释放

  封锁的实现:

    锁管理器可以实现为一个过程,它从事务接受消息并反馈消息。

    锁管理器使用以下数据结构:

      锁管理器为目前已加锁的每个数据项维护一个链表,每一个请求为链表中一条记录,按请求到达的顺序排列。

      它使用一个以数据项名称为索引的散列表来查找链表中的数据项(如果有的话)这个表叫做锁表

      一个数据项的链表中每一条记录表示由哪个事务提出的请求,以及它请求什么类型的锁,该记录还表示该请求是否已授予锁

    锁管理器这样处理请求:

      1 当一条锁请求消息到达时,如果相应数据项的链表存在,在该链表末尾增加一个记录,否则,新建一个仅包含该请求记录的链表

      2 当锁管理器收到一个事务的解锁消息时,它将与该事务相对应的数据项链表中的记录删除,然后检查随后的记录,有,看该请求能否被授权,

        能,锁管理器授权该请求并处理其后记录

      3 如果一个事务中止,锁管理器删除该事务产生的正在等待加锁的所有请求,一旦数据库撤销该事务,该中止事务持有的所有锁将被释放

  基于图的协议:

 

 

 

 

死锁处理:

  处理死锁问题主要有两种方法:

    1 死锁预防:保证系统永不进入死锁状态

    2 死锁检测和死锁恢复

  死锁预防:

    1 通过对加锁请求进行排序或要求同时获得所有的锁来保证不会发生循环等待

    2 每当有可能导致死锁时,进行事务回滚而不是等待加锁

    对所有的数据项强加一个次序,同时要求事务只能按次序规定的顺序封锁数据项,

    另一种方法:抢占与事务回滚:我们给每一个事务赋予唯一的时间戳,系统仅用时间戳来决定事务应当等待还是回滚

    两种基于时间戳的死锁预防机制:

      1 wait-die机制基于非抢占技术,当事务i申请的数据项当前被j持有,仅当i的时间戳小于j的时间戳(i比j老)时,i等待,否则i死亡(回滚)

      2 wound-die机制基于抢占技术,当事务a申请的数据项被b持有,仅当a的时间戳大于b的时间戳(a比b年轻时)时,允许a等待,否则,b回滚(被伤害)

      两种机制都面临的主要问题是可能发生不必要的回滚

    另一种方法基于锁超时,申请锁的事务至多等待一段给定的时间,若时间内未授予该事务锁,则称该事务超时,事务回滚并重启,基于超时的机制应有有限

  死锁检测与恢复:

    检查系统状态的算法周期性的激活,判断有无死锁发生,如果发生死锁,必须试着从死锁中恢复。

    系统必须:

      1 维护当前将数据项分配给事务的有关信息,以及任何尚未解决的数据项请求信息

      2 提供一个使用这些信息判断系统是否进入死锁状态的算法

      3 当检测算法判定存在死锁时,从死锁中恢复

    死锁检测:

      死锁可以用称为等待图的有向图来精确描述

    死锁恢复:

      1 选择牺牲者

        选择最小代价的事务:

          a 事务已计算了多久,在完成指定任务之前还将计算多长时间

          b 该事务已使用了多少数据项

          c 为完成事务还需使用多少数据项

          d 回滚时将牵扯多少事务

      2 回滚

        彻底回滚或部分回滚

      3 饿死

 

 

 

多粒度:

  

 

 

基于时间戳的协议:

  时间戳:

    实现时间戳有两种方式:

      1 系统时钟的值作为时间戳

      2 逻辑计数器的值

    每个数据项Q需要与两个时间戳值相关联:

      1 w-timestamp:成功执行write的所有事务的最大时间戳

      2 R-timestamp:成功执行read的所有事务的最大时间戳

    每当有新的read或write指令执行时,这些时间戳就更新

  时间戳排序协议:

    1 事务发出read:

      a 若T(事务时间戳)<w-timestamp,则事务需要读入的值已被覆盖,read操作被拒绝,回滚

      b 若T>=w-timestamp,则执行read操作,

        R-timestamp被设置成R-timestamp与T之间最大值

    2 事务发出write:

      a 若T<R-timestamp,则事务产生的值是先前所需要的值,且系统已假定该值不会再产生

        因此,write操作被拒绝,事务回滚

      b 若T<w-timestamp,则事务试图写入的值已过时,因此,write操作被拒绝,回滚

      c 其他情况,系统执行write操作,将w-timestamp设置为T

    由于事务发出read或write操作而被并发控制机制回滚,则系统赋予它新的时间戳并重新启动

    该协议可能产生不可恢复的调度,用以下几种方法之一来保证调度可恢复:

      * 在事务末尾执行所有的写操作能保证可恢复性和无级联性,这些操作必须具有下述意义

        的原子性:在写操作正在执行的过程中,任何事务都不许访问已写完的任何数据项

      * 可恢复性和无级联性也可以通过使用一个受限的封锁形式来保证,

        因此,对未提交数据项的读操作被推迟到更新该数据项的事务提交之后

      * 可恢复性可以通过跟踪未提交写操作来单独保证,一个事务读取了其他事务所写的数据,        只有在其他事务都提交之后,才能提交

  Thomas写规则:

    修改时间戳排序协议而得到一个新版本的协议,该协议在某些特定的情况下忽略过时的write操作

    协议中有关read操作的规则保持不变,但write有区别  

    这种修改叫Thomas写规则:

      1 若T<R-timestamp,则事务产生的值是先前所需要的值,且系统已假定该值不会再产生,        write操作被拒绝,回滚

      2 若T<w-timestamp,则事务试图写入的值已过时,这个write操作可忽略

      3 其他情况,执行write操作,将w-timestamp设置为T

    Thomas写规则实际上是通过删除事务发出的过时的write操作来使视图可串行性

 

 

 

基于有效性检查的协议:

  一种监控系统的机制

  有效性检查协议要求每个事务在其生命周期中按两个或三个阶段执行:

    1 读阶段:系统执行事务,各数据项值被读入并保存在事务的局部变量中,

      所有的write操作都是对局部变量进行的,并不对数据库进行真正的更新

    2 有效性检查阶段:对事务进行有效性检查,判断是否可以执行write操作而不违反可串行性

      如果事务有效性测试失败,则系统终止这个事务

    3 写阶段:若事务通过有效性检查,则保存任何写操作结果的临时局部变量值被复制到数据库中

  为进行有效性检测,我们需要知道事务的各个阶段何时进行,保留3个时间戳:

    1 start,事务开始执行的时间

    2 validation,开始有效性检查的时间

    3 finish,完成写阶段的时间

  利用validation而不是start作为事务的时间戳,是在冲突频率很低的情况下期望有更快的响应时间

  事务i的有效性测试要求任何满足T(k)<T(i)的事务k必须满足下面两条件之一:

    1 finish(k)<start(i)

    2 k和i的数据项集不相交

 

 

 

多版本机制

  多版本时间戳排序

    对于系统中的事务,我们将一个唯一的静态时间戳与之关联,记为T

    对于每个数据项Q,有一个版本序列<Q(1)、Q(2)、Q(m)>关联,每个版本包含三个数据字段:

      1 content 是Q版本的值

      2 W-timestamp是创建Q版本的事务的时间戳

      3 R-timestamp是所有成功地读取Q版本的事务的最大时间戳

    多版本时间戳排序机制:

      1 如果事务发出read,则返回Q的内容

      2 如果事务发出write,若T<R-timestamp,则事务回滚

                  若T=W-timestamp,则覆盖Q的内容

                  若T>R-timestamp,创建Q的一个新版本

    多版本时间戳排序机制不保证可恢复性和无级联性

  多版本两阶段封锁:

    

 

 

快照隔离:

  快照是一种特殊的并发控制机制,在商业和开源系统中广泛接受

  更新事务的有效性检验步骤:

    快照隔离有两个变种,都防止了更新丢失:

      a 先提交者获胜:

        1 检查是否有与T并发执行的事务,对于T打算写入的某些数据,该事务已经更新数据库

        2 如果有,T中止

        3 如果没有,T提交,将更新写入数据库

      b 先更新者获胜:

        系统采用一种仅用于更新操作的锁机制(读操作不受此影响,因为它们不获得锁)

        当事务试图更新一个数据项时,它请求该数据项的一个写锁,

        如果没有另一个并发事务持有该锁,获得锁后执行以下步骤:

          1 如果这个数据项已经被任何并发事务更新,则T中止

          2 否则T执行其操作,可能包括提交

        如果另一个并发事务j已经持有该数据项的写锁,则T不能执行,并且执行以下规则:

          1 等待直到j中止或提交

            a 如果j中止,则事务获得锁,执行前面的步骤

            b 如果j提交,则事务中止

        当事务提交或中止时,锁被释放

  串行化问题       

 

 

 

插入操作、删除操作与谓词读:

  删除:

    1 在两阶段封锁协议下,一数据项可以删除之前,在该数据项上必须请求加排他锁

    2 在时间戳排序协议下,必须执行测试,事务T发出delete:

      * 如果T<R-timestamp,delete操作被拒绝,T回滚

      * 如果T<W-timestamp,delete操作被拒绝,T回滚

      否则,执行delete操作

  插入:

    1 在两阶段封锁协议下,如果执行insert操作,就在新创建的数据项Q上赋予排他锁

    2 在时间戳排序协议下,把R-timestamp和W-timestamp值设置成T

  谓词读和幻象现象

 

 

 

实践中的弱一致性级别

  二级一致性:

    目的:是在不必保证可串行性的前提下防止发生级联中止

 

 

 

索引结构中的并发:

posted @ 2013-10-28 12:54  褐色键盘  阅读(766)  评论(0)    收藏  举报