目录
一、并发控制概述
事务的并行执行
交叉并发方式(单处理机系统) 并没有真正地并行运行 本章讨论
同时并发方式(多处理机系统)
当多个用户并发地存取数据库时就会产生多个事务同时存取同一数据的情况。
若对并发操作不加控制就可能会存取和存储不正确的数据,破坏事务的一致性和数据库的一致性。
所以,DBMS必须提供并发控制机制。
并发控制机制是衡量一个DBMS性能的重要标志之一。
并发操作带来数据不一致性
丢失修改 | 不可重复读 | 读”脏”数据 |
两个事务T1和T2读入同一数据并修改 | 事务T1读取数据后,事务T2 执行更新(修改 删除 插入)操作 幻影现象:T2进行了删除或者插入 | 事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销 |
写 写 | 读 写 | 写(rollback) 读 |
并发控制的主要技术
封锁(Locking)
时间戳(Timestamp)
乐观控制法
多版本并发控制(MVCC)
二、封锁
所谓封锁就是事务T在对某个数据对象(如表、记录)操作之前,先向系统发出请求,对其加锁。
基本的封锁类型
排他锁(exclusive locks,简称X锁) 不允许其它事务再加锁
共享锁(share locks,简称S锁) 其它事务可以加S锁
锁的相容矩阵(compatibility matrix)
三、封锁协议--三级封锁协议
一级封锁协议 防止丢失修改
事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。
事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)
二级封锁协议 防止丢失修改和读“脏”数据
在一级封锁协议基础上增加事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。
三级封锁协议 止丢失修改、读“脏”数据和不可重复读
在一级封锁协议基础上增加事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放S锁
二级与三级的区别在于二级在读完后就释放S锁,而三级在事务结束后才释放。
不同级别的封锁协议和一致性保证
四、活锁和死锁
活锁:某个事务永远等待
死锁:略
预防死锁的方法: 都行不通
一次封锁法 事务一次将所有要使用的数据加锁
顺序封锁法 对数据对象规定一个封锁顺序
诊断并解除死锁的方法:
超时法 事务等待时间超过了规定时限
等待图法 事务等待图存在回路
五、并发调度的可串行性
可串行化调度
多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行这些事务时的结果相同,称这种调度策略为可串行化(serializable)调度。
可串行性(serializability)是并发事务正确调度的准则。
一个给定的并发调度,当且仅当它是可串行化的,才认为是正确调度
正确的调度⇔可串行化调度
冲突可串行化调度
一个调度Sc在保证冲突操作的次序不变的情况下,通过交换两个事务不冲突操作的次序得到另一个调度Sc’,如果Sc’是串行的,称调度Sc是冲突可串行化的调度。
冲突操作:不同事务对同一数据的读写操作、写写操作
其他操作:除上述以外的操作 事务对不同数据的操作 同一事物对同一数据的读读操作
若一个调度是冲突可串行化,则一定是可串行化的调度。
判断是否为冲突可串行化调度:优先图算法
六、两段锁协议
两段锁协议是指每个事务必须分为两个阶段对数据项进行加锁和解锁。
“两段”锁的含义是,事务分为两个阶段:
第一阶段获得封锁,也称为扩展阶段(growing phase)
事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁
第二阶段释放封锁,也称为收缩阶段(shrinking phase)
事务可以释放任何数据项上的任何类型的锁,但是不能再申请任何锁
结论:若并发执行的所有事务都遵守两段锁协议,则对这些事务的任何并发调度都是可串行化的。
遵守两端锁协议的事务也可能会产生死锁
七、封锁的粒度
封锁粒度(granularity)指封锁对象的大小。
粒度越大,数据库所能够封锁的数据单元就越少,并发度就越小,系统开销也越小;
粒度越小,并发度较高,但系统开销也就越大。
多粒度封锁 (Multiple Granularity Locking)
在一个系统中同时支持多种封锁粒度供不同的事务选择的封锁方法称为多粒度封锁。
多粒度树
多粒度封锁协议
在多粒度封锁中一个数据对象可能以两种方式封锁
显式封锁 是应事务的要求直接加到数据对象上的锁;
隐式封锁 是该数据对象没有被独立加锁,是由于其上级结点加锁而使该数据对象加上了锁;
显式封锁和隐式封锁的效果一样。
系统检查封锁冲突时不仅要检查显式封锁还要检查隐式封锁。
一般地,对某个数据对象加锁,系统要检查该数据对象上有无显式封锁与之冲突;再检查其所有上级结点,看本事务的显式封锁是否与该数据对象上的隐式封锁冲突(由于上级结点已加的封锁造成的);看它们的显式封锁是否与本事务的隐式封锁(将加到下级结点的封锁)冲突。
特点:检查方法效率很低!
解决方案:引入意向锁(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锁)。
意向锁的相容矩阵
S不能与含X的一起
X不能与任何一起
IS只与X不可以
SIX只与IS可以
IX IX可以 IX SIX 不可以
具有意向锁的多粒度封锁方法
申请封锁时应该按自上而下的次序进行;
释放封锁时则应该按自下而上的次序进行。