文章目录
-
- 背景
- 并发控制概述
-
-
- DBMS并发控制的责任:
- 调度:
- 并发操作会带来的问题——数据的三种不一致?
- 并发控制的主要技术?
- 封锁
-
- 封锁协议
-
- 什么是封锁协议?协议规定的是哪三个部分?
- 三级封锁协议
-
- 活锁和死锁
-
-
- 避免活锁的简单方法:
- 解决死锁问题的两类主要方法:
- 并发调度的可串行性
-
-
-
- 什么调度是正确的?
- 如何判断冲突可串行化?优先图算法。
- 两段锁协议
- 可串行化调度小结
- 封锁的粒度
-
-
- 封锁粒度:
-
- 封锁的对象:
- 封锁粒度与系统的并发度和并发控制的开销密切相关。
- 如何选择封锁粒度
- 多粒度封锁
-
- 多粒度封锁协议:
- 意向锁:
- 意向锁的相容矩阵:
- 具有意向锁的多粒度封锁方法
- 例题:
背景
事物的串行执行: 每个时刻只有一个事务运行,其它事务必须等到结束以后方能运行。
问题:许多系统资源将处于空闲状态,因此为了充分利用系统资源,发挥数据库共享资源的特点,应该允许多个事务并行执行。
事务的并行执行:
- 交叉并发方式(单处理机系统):并发事务的并行操作轮流交叉运行。
- 同时并发方式(多处理系统):每个处理及运行一个事务,受制于硬件环境。
为什么DBMS必须提供并发控制机制?
当多个用户并发地存取数据库时就会产生多个事务同时存取同一数据的情况,若对并发操作不加控制就可能会存取和存储不正确的数据,破坏事物的一致性和数据库的一致性。并发控制机制是衡量一个DBMS性能的重要标志之一。
并发控制概述
事务是并发控制的基本单位。
DBMS并发控制的责任:
- 保证事务的隔离性。
- 保证事务的一致性。
- 对并发操作进行正确的调度。
调度:
reading, writing, aborting, committing的组合序列。
并发操作会带来的问题——数据的三种不一致?
- 丢失修改(T1写,T2写)【T1和T2读入同一数据并修改,T2用的数据并不是T1的数据】
- 不可重复读(T1读,T2写)【T1读取数据,T2执行更新操作(修改删除插入三种),影响了T1读取的数据】
- 读“脏”数据(T1写,T2读)【事务T1修改某一数据并写入,事务T2读取该数据之后,事务T1因某种原因被撤销,那么T2此时使用的数据就和数据库中的数据不一致】
并发控制机制就是利用正确的方式调度并发操作, 使一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性。
并发控制的主要技术?
- 封锁(Locking)
- 时间戳(Timestamp)
- 乐观控制法
- 多版本并发控制(MVCC)
封锁
概念: 事务T在对某个数据对象(如表、记录)操作之前,先向系统发出请求,对其加锁。
- 加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务就不能更新此数据对象。
基本的封锁类型:
- 排他锁(X锁)
- 若事务T给数据对象A加上排他锁X锁,则是允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A的锁。
- 保证其他事务在T释放A上的锁之前不能再读取和修改A。
- 共享锁(S锁)
- 若事务T给数据对象A加上S锁,则事务T可以读A但不能修改A,其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。
- 保证其他事务可以读A,但在T释放A上的锁之前不能对A做任何修改。
锁的相容矩阵?
封锁协议
什么是封锁协议?协议规定的是哪三个部分?
在运用X锁和S锁对数据对象加锁时,需要约定的规则。
(何时申请,持锁时间,何时释放)
三级封锁协议
一级封锁协议:
- 内容:事务T在修改数据A之前必须先对其加X锁,直到事务结束才释放。事务结束包含正常结束(COMMIT)和非正常结束(ROLLBACK)。
- 作用:防止丢失修改,并保证事务T是可恢复的。
- 短板:一级中,若仅仅是读数据不对其进行修改,是不需要加锁的,所以不能保证可重复读和不读脏数据。
二级封锁协议
- 内容:在一级封锁协议基础上,增加事务T在读取数据A之前必须先对其加S锁,读完后即可释放S锁。
- 作用:可防止丢失修改和读脏数据。
- 短板:由于读完数据后即可释放S锁,所以不能保证可重复读。
三级封锁协议:
- 在一级封锁协议基础上增加事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放S锁。
- 作用:可防止丢失修改、读“脏”数据和不可重复读。
活锁和死锁
活锁: 由于服务分配顺序无规定,某事物可能永远等待。
避免活锁的简单方法:
死锁: 两个或多个事务都已封锁了一些数据对象,然后又都请求对已为其他事务封锁的数据对象加锁,从而出现死等待。
解决死锁问题的两类主要方法:
- 预防死锁(不太适合数据库特点)。
- 一次封锁法:要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行。
- 问题:1、降低了系统的并发度;2、难于事先精确确定锁定对象。
- 顺序封锁法:预先对数据对象规定一个封锁顺序,所有事务都按整个顺序实行封锁。
- 允许发生死锁,但定期诊断死锁;若有则解除。(DBMS普遍采用的方法)
- 超时法:如果一个事务的等待时间超过了规定的时间,就认为发生了死锁。
- 优点:实现简单
- 缺点:1、可能误判;2、若时限设置过长,死锁发生后不容易发现。
- 等待图法:用事务等待图动态反映所有事务的等待情况。
- 事务等待图:一个有向图G=(T,U),T为结点的集合,每个结点表示正运行的事务;U为边的集合,每条边表示事务等待的情况。若T1等待T2,则T1、T2之间画一条有向边,从T1指向T2。
- 解除死锁:选择一个处理死锁代价最小的事务,将其撤消,释放此事务持有的所有的锁,使其它事务得以继续运行下去。
并发调度的可串行性
数据库管理系统对并发事务不同的调度可能会产生不同的结果。
什么调度是正确的?
- 串行调度
- 可串行化调度: 多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行这些事务时的结果相同,称这种调度策略为可串行化(serializable)调度。
可串行性(Serializability)是并发事务正确调度的准则。
如何判断一个n个并发事务的调度是正确的调度?
-
傻算方法:
- 计算出这n个事务的所有串行组合调度的结果,共有n! 次计算;
- 计算待判断调度的结果。若与之前某个串行调度的结果相同,则该调度为正确的调度,否则不是正确的调度。
-
冲突可串行化调度(充分条件):
冲突操作:指不同的事务对同一数据的读写和写写操作。
其它操作:…读读操作。
如何判断冲突可串行化?优先图算法。
-
构造一个有向图G=(N, E),其中
-
N={ T1, T2,…, Tn },Ti(I = 1, 2, …, n)表示事务Ti对应的结点;
-
E为不同结点之间有向边的集合。
-
有向边eij:Ti →Tj的定义如下:
如果出现以下任一种情形,则结点Ti到结点Tj(i≠j)之间存在一条有向边
– Wi(X)Rj(X),Ri(X)Wj(X),Wi(X)Wj(X)
-
该调度为冲突可串行化调度的充分必要条件为有向图G不存在回路
两段锁协议
DBMS普遍采用两段锁协议(2PL)实现并发调度的可串行性。
内容:每个事务必须分为两个阶段对数据项进行加锁和解锁。
- 第一阶段获得封锁,也称为扩展阶段。
- 事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁。
- 第二阶段释放封锁,也称为收缩阶段。
- 事务可以释放任何数据项上的任何类型的锁,但是不能再申请任何锁。
两段锁协议与防止死锁的一次封锁法:
- 一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行,因此一次封锁法遵守两段锁协议。
- 但是两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务可能发生死锁。
可串行化调度小结
正确的调度 ⇔ 可串行化调度(正确的调度 ⇔ 串行调度 正确吗?)
两类可串行化调度的充分非必要条件。
判定冲突可串行化调度的方法。
- 优先图算法
- 利用该算法可以很容易地构造冲突可串行化调度的例子
遵守两段锁协议可能发生死锁。
封锁的粒度
封锁粒度:
指封锁对象的大小。粗粒度vs细粒度
封锁的对象:
- 逻辑单元,物理单元
- 关系数据库中的逻辑单元
- 属性值、属性值的集合、元组、关系、索引项、整个索引、整个数据库
- 关系数据库中的物理单元
封锁粒度与系统的并发度和并发控制的开销密切相关。
如何选择封锁粒度
应考虑封锁开销和并发度两个因素。
- 需要处理某个关系的大量元组的用户事务 — 以关系为封锁粒度
- 需要处理多个关系的大量元组的用户事务 — 以数据库为封锁粒度
- 只处理少量元组的用户事务 — 以元组为封锁粒度
多粒度封锁
在一个系统中同时支持多种封锁粒度供不同的事务选择的封锁方法称为多粒度封锁。
多粒度封锁协议:
- 多粒度封锁协议允许多粒度树中的每个结点被独立地加锁。
- 对一个结点加锁意味着这个结点的所有后裔结点也被加以同样类型的锁
一般地,对某个数据对象加锁,系统要检查该数据对象上有无显式封锁与之冲突;再检查其所有上级结点,看本事务的显式封锁是否与该数据对象上的隐式封锁冲突(由于上级结点已加的封锁造成的);看它们的显式封锁是否与本事务的隐式封锁(将加到下级结点的封锁)冲突。
- 特点:检查方法效率很低!
- 解决方案:引入意向锁(intention lock)
意向锁:
含义:如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁。
用法:对任一结点加锁时,必须先对它的上层结点加意向锁。
作用:有了意向锁,DBMS就无须逐个检查下一级结点的显式封锁。
IS锁(意向共享锁, intent share lock)
- 如果对一个数据对象加IS锁,表示它的后裔结点拟(意向)加S锁。
- 例如:事务T1要对R1中某个元组加S锁,则要首先对关系R1和数据库加IS锁
IX锁(意向排他锁, intent exclusive lock)
- 如果对一个数据对象加IX锁,表示它的后裔结点拟(意向)加X锁。
- 例如:事务T1要对R1中某个元组加X锁,则要首先对关系R1和数据库加IX锁
SIX锁(共享意向排他锁, share intent exclusive lock)
- 如果对一个数据对象加SIX锁,表示对它加S锁,再加IX锁,即SIX = S+IX。
- 例:对某个表加SIX锁,则表示该事务要读整个表(所以要对该表加S锁),同时会更新个别元组(所以要对该表加IX锁)。
意向锁的相容矩阵:
具有意向锁的多粒度封锁方法
- 申请封锁时应该按自上而下的次序进行
- 释放封锁时则应该按自下而上的次序进行
例题: