第三章 事务处理
预备知识
事务:事务是用户定义的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的执行序列。
事务的ACID特性:原子性、一致性、隔离性与持续性。
事务的ACID特性可能遭到破坏的原因之一是多个事务对数据库的并发操作造成的。
为此,需要对并发操作进行控制。是一个用户事务的执行不受其他事务的干扰。
并发控制的主要技术有锁、时间戳、乐观控制法与多版本并发控制(MVCC)等。
锁
基本的锁有两种:写锁与读锁;
写锁:简称X锁,当事务T对数据对象A加上X锁后,则只有T能够读取与修改A,其他事务不能再对A加任何的锁,直到T将A上的锁释放。
读锁:简称S锁,当事务T对数据对象A加上S锁后,则事务T只能读A但是不能修改A,其他事务可以对A再加S锁但不能加X锁,直到T释放A上的S锁为止。
在使用X锁与S锁时,需要约定一些规则,这些规则称为封锁协议。下面介绍三级封锁协议。
1 | 一级:事务T在修改数据R之前必须先对其加X锁 |
活锁与死锁
活锁是指事务一直请求锁而未被系统分配。
死锁是指两个事务互相等待造成的。
死锁的预防
一次封锁法:每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行。
顺序封锁法:预先对数据对象规定一个封锁顺序,所有事务都按照这个顺序实施封锁。
预防的成本过高,数据库系统通常采用诊断死锁并在死锁出现后解除的方案。
死锁的诊断与解除
检测死锁的方法包括超时法与等待图法。其中,等待图法指并发控制系统周期性生成事务等待图,并进行检测,若图中发现回路,则表示系统发生了死锁。
通常解除死锁的方法为将代价最小的事务的所有资源释放,使得其他事务可以运行下去。
锁的粒度
锁的对象大小称为锁的粒度,锁的对象可以是属性,属性集合、元组、关系、索引项,整个索引甚至整个数据库这些逻辑单元。也可以是页、物理记录等物理单元。
锁的粒度与系统的并发度和并发控制的开销相关。若一个系统同时支持多种粒度的锁则是最理想的,这种锁称为多粒度锁。
使用多粒度锁,加锁需分析其对应的多粒度树;多粒度树以数据库为根节点,代表最大的锁粒度,叶节点则代表最小的锁粒度。
对多粒度树上的节点加锁意味着这个节点的所有后裔节点也被加锁,由于不是对其直接加锁,故称为隐式锁,而这个节点的锁称为显式锁。
那么,在对一个数据对象加锁时,既要考虑其所有上级节点,又要考虑其所有后裔节点。这种检查方法效率很低,为此引入意向锁
。
意向锁
对任一节点加锁时,必须先对它的上层节点加意向锁。三种常用的意向锁:意向共享锁(IS锁)、意向排他锁(IX锁)与共享意向排他锁(SIX锁)。
- 对一个节点加S锁,则需要先对该节点的所有上级节点加IS锁;
- 对一个节点加X锁,则需要先对节点的所有上级节点加IX锁;
- 若一个节点已经加S锁,其后裔节点要加X锁,则对该节点加SIX锁;
下面是三种意向锁加上读写锁的偏序关系。
一个事务在申请加锁时以强锁代替弱锁是安全的,加锁时应该自上而下进行,解锁时应该自下而上进行。