并发控制
目标:掌握基本概念和定义,理解并发控制的目的
并发控制概述⭐️
多事务执行的三种方式
- 事务串行执行
- 每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行
- 不能充分利用系统资源,发挥数据库共享资源的特点
- 交叉并发执行
- 并行事务轮流交叉运行
- 是单处理机系统中的并发方式,能够减少处理机的空闲时间,提高系统的效率
- 宏观:多个事务同时在执行;微观:一个时刻只有一个事务的操作在处理
- 同时并发方式
- 多处理机系统中,多个处理机可以同时运行多个事务,实现多个事务真正的并行运行
- 最理想的并发方式,但受制于硬件环境
并发操作带来的数据不一致性⭐️
- 丢失修改(lost update)
丢失修改是指事务1与事务2从数据库中读入同一数据并修改,事务2的提交结果破坏了事务1提交的结果, 导致事务1的修改被丢失。(W-W)
- 不可重复读(non-repeatable read)
不可重复读是指事务1读取数据后,事务2执行更新操作,使事务1无法再现前一次读取结果。(R-W)
- 读“脏”数据(dirty read)
事务1修改某一数据,并将其写回磁盘,事务2读取同一数据后,事务1由于某种原因被撤消,这时事务1已修改过的数据恢复原值,事务2读到的数据就与数据库中的数据不一致,是不正确的数据,又称为“脏”数据。(W-R)
封锁
什么是封锁
- 封锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁。加锁后,事务T就对该数据对象有了一定的控制, 在事务T释放它的锁之前,其它的事务不能更新此数据对象。
- 封锁是实现并发控制的一个非常重要的技术
两种封锁类型
- 排它锁(eXclusive lock,简记为X锁)
排它锁又称为写锁
若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁
- 共享锁(Share lock,简记为S锁)
共享锁又称为读锁
若事务T对数据对象A加上S锁,事务T可以读A但不能修改A,其它事务也只能再对A加S锁,而不能加X锁,直到T释放A上的S锁
锁的相容矩阵
Y=Yes,相容的请求
N=No,不相容的请求
什么是封锁协议
- 在运用X锁和S锁对数据对象加锁时,需要约定一些规则,这些规则为封锁协议
- 何时申请X锁或S锁
- 持锁时间
- 何时释放
三级封锁协议
- 一级封锁协议
事务T在修改数据W之前必须先对其加X锁,直到事务结束才释放。(读不加锁)
一级封锁协议可防止丢失修改
- 二级封锁协议
一级封锁协议基础上,事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁
二级封锁协议可以防止丢失修改和读“脏”数据
- 三级封锁协议
一级封锁协议基础上,事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放
三级封锁协议可防止丢失修改、读脏数据和不可重复读
活锁和死锁⭐️
什么是活锁
- 事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁后,系统首先批准了T3的请求,T2仍然等待。然后T4又请求封锁R,当T3释放了R上的封锁之后,系统又批准了T4的请求…T2可能永远等待。因为事务T2在不断的重复尝试获取锁R,所以这个就是活锁。
- 活锁有可能自行解开
如何避免活锁
- 采用先来先服务的策略:当多个事务请求封锁同一数据对象时,按请求封锁的先后次序对这些事务排队。该数据对象上的锁一旦释放,首先批准申请队列中第一个事务获得锁。
什么是死锁
- 事务T1获取了数据R1的排它锁,事务T2获取了数据R2的排它锁。事务T1需要获取数据R2的排它锁来完成事务,但数据R2的排它锁需要事务T2执行完才能释放,而事务T2需要获取数据R1的排它锁来完成事务,但数据R1的排它锁需要事务T1执行完才能释放。此时形成死锁。
- 在两个或多个任务中,如果每个任务锁定了其他任务试图锁定的资源,此时会造成这些任务永久阻塞,从而出现死锁。
- 除非某个外部进程断开死锁,否则死锁中的两个事务都将无限期等待下去。
解决死锁的方法
- 预防死锁
- 一次封锁法
要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行
一次封锁法存在的问题:降低并发度
- 顺序封锁法
顺序封锁法是预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁
顺序封锁法存在的问题:维护成本高
在操作系统中广为采用的预防死锁的策略并不很适合数据库
DBMS在解决死锁的问题上更普遍采用的是诊断并解除死锁的方法
- 死锁的诊断与解除
- 超时法
如果一个事务的等待时间超过了规定的时限,就认为发生了死锁
- 等待图法
用事务等待图动态反映所有事务的等待情况
事务等待图是一个有向图G=(T,U),T为结点的集合,每个结点表示正运行的事务,U为边的集合,每条边表示事务等待的情况。若T1等待T2,则T1,T2之间划一条有向边,从T1指向T2
并发控制子系统周期性地(比如每隔1 min)检测事务等待图。如果发现图中存在回路,则表示系统中出现了死锁
- 解除死锁
选择一个处理死锁代价最小的事务, 将其撤消,释放此事务持有的所有的锁,使其它事务能继续运行下去。
并发调度的可串行性
可串行性的定义
- 几个事务的并行执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同。 这种并行调度策略称为可串行化(Serializable) 的调度
- 可串行性是并行事务正确性的唯一准则
什么是冲突操作
- 冲突操作是指读写操作和写写操作
什么是冲突可串行化调度
- 一个调度Sc在保证冲突操作的次序不变地情况下,通过交换两个事务不冲突操作的次序得到另一 个调度Sc’ ,如果Sc’是串行的,则称调度Sc为冲突可串行化的调度
- 一个调度是冲突可串行化的,则一定是可串行化的调度。 (充分条件)
例:调度Sc1=r1(A)w1(A)r2(A) w2(A)r1(B)w1(B) r2(B)w2(B)
通过2次交换:
w2(A)与r1(B)w1(B)交换: r1(A)w1(A)r2(A) r1(B)w1(B) w2(A) r2(B)w2(B)
r2(A)与r1(B)w1(B)交换: r1(A)w1(A) r1(B)w1(B) r2(A) w2(A) r2(B)w2(B)
得到Sc2=r1(A)w1(A) r1(B)w1(B) r2(A) w2(A) r2(B)w2(B)
Sc2等价于一个串行调度T1,T2;所以Sc1是冲突可串行化调度。
两段锁协议
两段锁协议的内容
- 在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁
- 在释放一个封锁之后,事务不再获得任何其他封锁
所有遵守两段锁协议的事务,其并行执行的结果一定是正确的
事务遵守两段锁协议是可串行化调度的充分条件,而不是必要条件。可串行化的调度中,不一定所有事务都必须符合两段锁协议。
两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务可能发生死锁
多粒度封锁⭐️
什么是封锁粒度
- X锁和S锁都是加在某一个数据对象上的
- 封锁的对象:逻辑单元,物理单元
例:在关系数据库中,封锁对象:
逻辑单元: 属性值、属性值集合、元组、关系、索引项、整个索引、整个数据库等
物理单元:页(数据页或索引页)、物理记录等
- 封锁对象可以很大也可以很小
例: 对整个数据库加锁 对某个属性值加锁
- 封锁对象的大小称为封锁的粒度(Granularity)
什么是多粒度封锁
- 在一个系统中同时支持多种封锁粒度供不同的事务选择
什么是多粒度树
- 以树形结构来表示多级封锁粒度
- 根结点是整个数据库,表示最大的数据粒度
- 叶结点表示最小的数据粒度
显示封锁和隐式封锁
- 在多粒度封锁中一个数据对象可能以两种方式封锁:显式封锁和隐式封锁
- 显式封锁: 直接加到数据对象上的封锁
- 隐式封锁: 由于其上级结点加锁而使该数据对象加上了锁
- 显式封锁和隐式封锁的效果是一样的
什么是意向锁
- 对任一结点加基本锁,必须先对它的上层所有结点加意向锁
- 如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁
- 意向锁可以提高对某个数据对象加锁时系统的检查效率
例:对任一元组 r 加锁,先对关系R加意向锁
事务T要对关系R加X锁, 系统只要检查根结点数据库和关系R是否已加了不相容的锁,不需要搜索和检查R中的每一个元组是否加了X锁
三种意向锁⭐️
- 意向共享锁(Intent Share Lock,简称IS锁)
例:要对某个元组加S锁,则要首先对关系和数据库加IS锁
- 意向排它锁(Intent Exclusive Lock,简称IX锁)
例:要对某个元组加X锁,则要首先对关系和数据库加IX锁。
- 共享意向排它锁(Share Intent Exclusive Lock,简称SIX锁)
例:对某个表加SIX锁,则表示该事务要读整个表(所以要对该表加S锁),同时会更新个别元组(所以要对该表加IX锁)
意向锁的相容矩阵
小结
- 数据共享与数据一致性是一对矛盾
- 数据库的价值在很大程度上取决于它所能提供的数据共享度
- 数据共享在很大程度上取决于系统允许对数据并发操作的程度
- 数据并发程度又取决于数据库中的并发控制机制
- 另一方面,数据的一致性也取决于并发控制的程度。 施加的并发控制愈多,数据的一致性往往愈好
- 数据库的并发控制以事务为单位
- 数据库的并发控制通常使用封锁机制
- 两类最常用的封锁
- 不同级别的封锁协议提供不同的数据一致性保证,提供不同的数据共享度
- 三级封锁协议
- 并发控制机制调度并发事务操作是否正确的判别准则是可串行性
- 并发操作的正确性则通常由两段锁协议来保证。
- 两段锁协议是可串行化调度的充分条件,但不是必要条件
- 对数据对象施加封锁,带来问题
- 活锁: 先来先服务
- 死锁:
- 预防方法
- 一次封锁法
- 顺序封锁法
- 死锁的诊断与解除
- 超时法
- 等待图法
- 不同的数据库管理系统提供的封锁类型、封锁协议、达到的系统一致性级别不尽相同。但是其依据的基本原理和技术是共同的