多用户数据库系统:允许多个用户同时使用同一个数据库的数据库系统
交叉并发方式:在单处理机系统中,事务的并行执行实际上是这些并行事务的并行操作轮流交叉运行
同时并发方式:在多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同时运行多个事务,实现多个事务真正的并行运行
并发控制机制是衡量一个数据库管理系统性能的重要标志之一
事务是并发控制的基本单位
并发控制的主要技术有封锁、时间戳、乐观控制法和多版本并发控制……
数据的不一致性
并发操作带来的数据不一致性包括丢失修改、不可重复读和读”脏“数据
丢失修改
两个事务 T1 和 T2 读入同一数据并修改,T2 提交的结果破坏了 T1 提交的结果,导致 T1 的修改被丢失
不可重复读
指事务 T1 读取数据后,事务 T2 执行更新数据,使 T1 无法再现前一次读取结果
一个事务先后两次读数据
具体情况
- 事务 T1 读取某一数据后,事务 T2 对其进行了修改,当事务 T1 再次读该数据时,得到与前一次不同的值
- 事务 T1 按一定条件从数据库中读取了某些数据记录后,事务 T2 删除了其中部分记录,当 T1 再次按相同条件读取数据时,发现某些记录神秘地消失了
- 事务 T1 按一定条件从数据库中读取某些数据记录后,事务 T2 插入了一些记录,当 T1 再次按相同条件读取数据时,发现多了一些记录
2、3 有时称为幻影现象
读“脏”数据
指事务 T1 修改某一数据并将其写回磁盘,事务 T2 读取同一数据后,T1 由于某种原因被撤销,这时被 T1 修改过地数据恢复原值,T2 读到的数据与数据库中的数据不一致,则 T2 读到的数据为“脏”数据,即不正确的数据
产生上述三类数据不一致性的主要原因是并发操作破坏了事务的隔离性
并发控制机制是用正确的方式调度并发操作,使一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性
封锁
封锁是实现并发控制的一个非常重要的技术
封锁是事务 T 在对某个数据对象操作之前,先向系统发出请求,对其加锁。加锁后事务 T 对该数据对象有了一定的控制,在事务 T 释放它的锁之前,其他事务不能更新此项数据对象
确切的控制由封锁的类型决定,基本的封锁类型有:排他锁(X 锁)和共享锁(S 锁)
封锁类型
- 排他锁,又称写锁,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 上的 S 锁之前不能对 A 做任何修改
封锁协议
一级封锁协议
内容:事务 T 在修改数据 R 之前必须对其加 X 锁,直到事务结束才释放
作用:防止丢失修改,保证事务 T 是可恢复的
二级封锁协议
内容:在一级封锁协议基础上增加,事务 T 在读取数据 R 之前必须先对其加 S 锁,读完后即可释放 S 锁
作用:防止丢失修改、防止读“脏”数据
三级封锁协议
内容:在一级封锁协议的基础上增加,事务 T 在读取数据 R 之前必须先对其家 S 锁,直到事务结束才释放
作用:防止丢失修改、防止读“脏”数据、防止不可重复读
三级协议的区别
三级协议的主要区别在于什么操作需要申请封锁,何时释放锁(即持锁时间)
封锁协议的级别越高,一致性程度越高
活锁
一直等待解锁
解决方法
避免活锁的简单方法是采用先来先服务的策略
死锁
相互等待对方解锁
解决方法
- 采取一定措施预防死锁的发生
- 允许发生死锁,采用一定手段定期诊断系统中有无死锁,若有则解除之
死锁预防
一次封锁法
实施:要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行
存在的问题:
- 一次将以后要用到的全部数据加锁,扩大封锁的范围,降低系统的并发度
- 数据库中数据不断变化,原来不要求封锁的数据在执行过程中可能变成封锁对象,很难事先精确地确定每个事务所要封锁地数据对象,故只能扩大封锁范围,将事务在执行过程中可能要封锁地数据对象全部加锁,进一步降低并发度
顺序封锁法
实施:预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实施封锁
存在的问题:
- 数据库系统中封锁的数据对象极多,且随数据的插入、删除等操作不断变化,维护这样的资源封锁顺序非常困难,成本很高
- 事务的封锁请求可以随着事务的执行而动态决定,很难事先确定每一个事务要封锁哪些对象,很难按规定的顺序施加封锁
死锁的诊断与解除
数据库系统中,诊断死锁的方法和操作系统类似,一般使用超时法或事务等待图法
死锁的诊断
超时法
实施:如果一个事务的等待时间超过了规定的时限,就认为发生了死锁
存在的问题:
- 有可能误判死锁
- 时限若设置太长,死锁发生后不能及时发生
等待图法
由事务等待图可知,死锁的情况可以多种多样
死锁的解除
两段锁协议
遵守两段锁协议的一定是一个可串行化调度
不遵守两段锁协议的可能是可串行化调度,也可能不是
内容
所有事务必须分两个阶段对数据项加锁和解锁
- 在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁
- 在释放一个封锁之后,事务不再申请和获得其他封锁
含义
事务分为两个阶段,第一阶段是获得封锁,也称为扩展阶段,在这个阶段,事务可以申请获得任何数据项上的任何类型的锁,但不能释放任何锁;第二阶段是释放锁,也称为收缩阶段,在这个阶段,事务可以释放任何数据项上的任何类型的锁,但不能再申请任何锁
事务遵守两段锁协议是可串行化调度的充分条件,而不是必要条件
封锁的粒度
定义:封锁对象的大小
封锁对象:
- 逻辑单元:属性值、属性值的集合、元组、关系、索引项、整个索引直至整个数据库
- 物理单元:页(数据页或索引页)、物理记录……
封锁粒度与系统的并发度和并发控制的开销密切相关
封锁的粒度越大,数据库所能够封锁的数据单元就少,并发度就越小,系统开销越小;反之,封锁的粒度越小,并发度较高,系统开销越大
多粒度封锁:在一个系统中同时支持多种封锁粒度供不同的事务选择
选择封锁粒度时应同时考虑封锁开销和并发度两个因素,适当选择封锁粒度以求得最优的效果
多粒度封锁
定义多粒度树
多粒度树的根结点是整个数据库,表示最大的数据粒度,叶结点表示最小的数据粒度
多粒度封锁协议
内容:允许多粒度树中的每个结点被独立地加锁,对一个结点加锁意味着这个结点的所有后裔结点也被加以同样类型的锁
多粒度封锁中一个数据对象可能以两种方式封锁,显式封锁和隐式封锁
- 显式封锁:应事务的要求直接加到数据对象上的锁
- 隐式封锁:该数据对象没有被独立加锁,是由于其上级结点加锁而使该数据对象加上了锁
多粒度封锁方法中,显式封锁和隐式封锁的效果一样,系统检查封锁冲突时不仅要检查显式加锁还要检查隐式封锁
对某个数据对象加锁,系统要检查该数据对象上有无显式封锁与之冲突;再检查其所有上级结点,看本事务的显式封锁是否与该数据对象上的隐式封锁(由于上级结点已加的封锁造成的)冲突;还要检查其所有下级结点,看它们的显式封锁是否与本事务的隐式(将加到下级结点的封锁)封锁冲突
意向锁
作用:数据库管理系统不需要逐个检查下一级结点的显式锁
含义:如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁
种类:意向共享锁(IS 锁),意向排他锁(IX 锁),共享意向排他锁(SIX 锁)
IS 锁
如果对一个数据对象加 IS 锁,表示它的后裔结点拟(意向)加 S 锁
IX 锁
如果对一个数据对象加 IX 锁,表示它的后裔结点拟(意向)加 X 锁
SIX 锁
如果对一个数据对象加 SIX 锁,表示对它加 S 锁,再加 IX 锁,即 SIX=S+IX
例子:对某个表加 SIX 锁,则表示该事务要读整个表(故对该表加 S 锁),同时会更新个别元组(故对该表加 IX 锁)
具有意向锁的多粒度封锁方法提高了系统的并发度,减少了加锁和解锁的开销
并发调度的可串行性
可串行化调度
定义:多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行这些事务时的结果相同
可串行性是并发事务正确调度的准则
冲突可串行化调度
冲突操作:指不同的事务对同一个数,据的读写操作和写写操作
不同事务的冲突操作和同一事务的两个操作是不能交换的
定义:一个调度 Sc 在保证冲突操作的次序不变的情况下,通过交换两个事务不冲突操作的次序得到另外一个调度 Sc' ,如果 Sc' 是串行的,称调度 Sc 为冲突可串行化的调度
若一个调度是冲突可串行化,则一定是可串行化的调度
冲突可串行化调度是可串行化调度的充分条件,不是必要条件