当前位置:   article > 正文

并发控制——封锁、活锁和死锁_并发控制 rollback 怎么枷锁

并发控制 rollback 怎么枷锁

封锁

  • 封锁就是事务T在对某个数据对象(表、记录等)操作之前,先向系统发出请求,对其枷锁
  • 加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象
  • 封锁是实现并发控制的一个非常重要的技术

封锁类型

  • 基本封锁类型
    • 排它锁(eXclusive lock,简称X锁)
    • 共享锁(Share lock,简称S锁)

排它锁

  • 排它锁又称为写锁X锁
    • 若事务T1对数据对象A加上X锁,则只允许T1读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T1释放A上的X锁

共享锁

  • 共享锁又称为读锁S锁
    • 若事务T1对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T1释放A上的S锁

封锁类型的相容性

T_{1}
T_{2}XS-
XNNY
SNYY
-YYY

Y=Yes,相容的请求
N=No,不相容的请求

封锁粒度

  • X锁S锁都是加在某一个数据对象上的
  • 封锁的数据对象可以是逻辑单元
    • 属性值、属性值集合、元组、关系、索引项、整个索引、整个数据库等
  • 封锁的数据对象也可以是物理单元
    • 页(数据页或索引页)、块等
  • 封锁对象可以是大或者很小
    • 对整个数据库加锁
    • 对某个属性值加锁
  • 封锁对象的大小称为封锁的粒度
  • 封锁粒度与系统的并发度和并发控制的开销密切相关
封锁的粒度被封锁的对象并发度系统开销
  • 选择封锁粒度时必须同时考虑开销并发度两个因素,进行权衡,以求的最优的效果

封锁粒度一般原则

  • 需要处理大量元组的用户事务
    • 关系为封锁单元
  • 需要处理多个关系的大量元组的用户事务
    • 数据库为封锁单位
  • 只处理少量元组的用户事务
    • 元组为封锁事务

封锁协议

  • 在运用X锁和S锁数据对象加锁时,需要约定一些规则,这些规则为封锁协议(Locking Protocol)
    • 何时申请X锁或S锁
    • 持锁时间
    • 何时释放
  • 两种封锁协议
    • 三级封锁协议——保证数据一致性
    • 两段锁协议——保证并行调度可串行型

三级封锁协议

  • 一级封锁协议
    • 事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放
      • 正常结束(commit)
      • 非正常结束(rollback)
    • 一级封锁协议可防止丢失修改,并保证事务T是可恢复的
    • 在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所有它不能保证可重复读和不读“脏”数据

 

  • 二级封锁协议
    • 一级封锁协议加上事务T在读取数据R之前必须先对其加S锁读完后即释放S锁
    • 二级封锁协议可以防止丢失修改读“脏”数据

 

  • 三级封数据锁协议
    • 一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放
    • 三级封锁协议可防止丢失修改读“脏”数据不可重复读

三级协议的主要区别

什么操作需要申请封锁以及何时释放锁(持锁时间)

X锁S锁一致性保证
操作结束释放事务结束释放操作结束释放事务结束释放不丢失修改不读“脏”数据可重复读
一级封锁协议
二级封锁协议
三级封锁协议

两段锁协议

  • 可串行型是并行调度正确性的唯一准则
  • “两段”锁的含义
    • 在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁
    • 在释放一个封锁之后,事务不再获得任何其他封锁
  • 事务分为两个阶段
    • 第一阶段是获得封锁,称为扩展阶段
    • 第二阶段是释放封锁,称为收缩阶段
  • 事务1的封锁序列:SlockA...SlockB...XlockC...UnlockB...UnlockA...UnlockC 遵守2PL
  • 事务2的封锁序列:SlockA...UnlockA...SlockB...XlockC...UnlockC...UnlockB 不遵守2PL
  • 并行执行的所有事务均遵守两段锁协议,则对这些事务的所有并行调度策略都是可串行化的
  • 所有遵守两段锁协议的事务,并行执行的结果一定是正确的
  • 事务遵守两段锁协议是可串行化调度的充分条件,而不是必要条件
  • 即可串行化的调度中,不一定所有事务都必须符合两段锁协议

死锁和活锁

  • 封锁技术可以有效地解决并行操作的一致性问题
  • 但也带来了一些新的问题
    • 死锁
    • 活锁

活锁

  • 什么是活锁
    • 系统可能使某个事务永远处于等待状态,得不到封锁的机会这种现象称为“活锁”

  • 如何避免活锁 
    • 采用先来先服务的策略
      • 当多个事务请求封锁同一个数据对象时,封锁子系统按请求封锁的先后次序对这些事务排队
      • 该数据对象上的锁一旦释放,首先批准申请队列中第一个事务获得锁

死锁

  • 什么是死锁
    • 系统中有两个或两个以上的事务都处于等待状态,并且每个事务都在等待其中另一个事务解除封锁,它才能继续执行下去,结果造成任何一个事务都无法继续执行,这种现象称系统进入了“死锁”

  •  解决死锁的两类方法
    • 死锁的预防
      • 产生死锁的原因是两个或多个事务都已经封锁了一些数据对象,然后又都请求对已为其它事务封锁的数据对象加锁,从而出现死等待
      • 预防死锁的发生就是要破坏产生死锁的条件
      • 预防死锁的方法
        • 一次封锁法
          • 一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行
          • 一次封锁法存在的问题:
            • 降低并发度
              • 一次就将以后要用到全部数据加锁,势必扩大了封锁的范围从而降低了系统的并发度
            • 难于事先精确确定封锁对象
              • 数据库中数据是不断变化的,原来不要求封锁的数据,在执行过程中可能会变成封锁对象,所以难事先精确地确定每个事务所要封锁的数据对象
        • 顺序封锁发
          • 顺序封锁是预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁
          • 顺序封锁法存在的问题:
            • 维护成本高
              • 数据库系统中可封锁的数据对象极其众多,并且随数据的插入、删除等操作而不断地变化,要维护这样极多而且变化的资源的封锁顺序非常困难,成本很高
            • 难于实现
              • 事务的封锁请求可以随着事务的执行而动态地决定,很难事先确定每一个事务要封锁哪些对象,因此也很难按规定的顺序去施加封锁
              • 例子:规定数据对象的封锁顺序为ABCDE,事务T_{3}起初要求封锁数据对象BCE,但当它封锁了后,发现还需要封锁A,这样就破坏了封锁顺序​​​​​​
    • 结论
      • 在操作系统中广为采用的预防死锁的策略并不很适合数据库的特点
      • DBMS在解决死锁的问题上更普遍采用的是诊断并解除死锁的方法
    • 死锁的诊断与解除
      • 诊断方法
        • 有DBMS的并发控制子系统定期监测系统中是否存在死锁,一旦检测到死锁,就要设法解除
        • 超时法
          • 如果一个事务的等待时间超过了规定的时限,就认为发生了死锁
          • 优点:实现简单
          • 缺点:有可能误判死锁、时限若设置的太长,死锁发生后不能及时发现
        • 等待图法
          • 用事务等待图动态反映所有事务的等待情况
            • 事务等待图是一个有向图G= \left ( T,U \right )
            • T为结点的集合,每个结点表示正运行的事务
            • U为边的集合,每条边表示事务等待的情况
            • T_{1}等待T_{2},则T_{1},T_{2}之间划一条有向边,从T_{1}指向T_{2}
          • 并发控制子系统周期性地(如每个1min)检测事务等待图,如果发现图中存在回路,则表示系统中出现了死锁
      • 死锁的解除
        • ​​​​​​​解决死锁
          • ​​​​​​​选择一个处理死锁代价最小的事务,将其撤销
          • 释放此事务持有的所有锁,使其它事务能继续运行下去

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/771998
推荐阅读
相关标签
  

闽ICP备14008679号