Bootstrap

数据库系统之并发控制(重点标记)

1. 并发控制概述

事务是并发控制的基本单位,并发控制机制的任务是:

  1. 对并发操作进行正确调度。
  2. 保证事务的隔离性。
  3. 保证数据库的一致性。
  • 数据不一致及其原因

并发操作带来的数据不一致性主要包括丢失修改,不重复读和读“脏”数据。产生三类数据不一致的主要原因是并发操作破坏了事务的隔离性。并发控制就是要用正确的方式调度并发控制,使一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性。

并发控制的主要技术有封锁,时间戳,乐观控制法,商用的DBMS一般都采用封锁方法。

2. 封锁

(1) 定义

封锁是事务T在对某个数据对象例如表,记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其他事务不能更新此数据对象。

(2) 分类

基本的封锁类型有两种:排他锁(简称X锁),和共享锁(简称S锁)。

  • 排他锁

排他锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型锁,直至T释放A上的锁为止。

  • 共享锁

共享锁又称为读锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直至T释放A上的S锁为止。

3. 封锁协议

在运用X锁和S锁这两种基本封锁对数据对象加锁时,还需要约定一些规则。例如何时申请X锁和S锁,持锁时间,何时释放等。这些规则称为封锁协议。

(1) 一级封锁协议

一级封锁协议是指事务T在修改数据R之前必须先对其加X锁,直至事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。

(2) 二级封锁协议

二级封锁协议是指在一级封锁协议基础上增加事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。二级封锁协议除防止了丢失修改,还可进一步防止读“脏”数据。

(3) 三级封锁协议

三级封锁协议是指在一级封锁协议的基础上增加事务T在读取数据R之前必须先对其加S锁,直至事务结束才释放。三级封锁协议除了防止丢失修改和读“脏”数据外,还能进一步防止了不可重复读。

三级封锁可总结为下表:

4. 活锁与死锁

(1) 活锁

  • 定义

如果事务T1封锁了数据R,事务T2又封锁了R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准T3的请求,R2仍然等待。然后T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求......T2有可能永远在等待,这就是活锁的情形。

  • 避免的办法

避免活锁的简单方法是采用先来先服务的策略。当多个事务请求封锁同一数据对象时,封锁子系统按请求封锁的先后次序对事务排队,数据对象上的锁一旦释放就批准申请队列中第一个事务获得锁。

(2) 死锁

  • 定义

如果事务T1封锁了数据R1,T2封锁了数据R2,然后T1又申请封锁R2,因T2已经封锁了R2,于是T1等待T2释放R2上的锁;接着T2又申请封锁R1,因T1已封锁了R1,T2也只能等待T1释放R1上的锁。所以就造成了相互等待的僵局。

  • 避免的方法

在数据库中解决死锁问题主要有两类方法,一类方法是采取一定措施来预防死锁的发生,另一类方法是允许发生死锁,采取一定手段定期诊断系统中有无死锁,若有则解除之。



死锁的预防

在数据库中,产生死锁的原因是两个或多个事务都已封锁了一些数据对象,然后又都请求对已被其他事务封锁的数据对象加锁,从而出现死等待。防止死锁的发生其实就是要破坏产生死锁的条件。预防死锁通常有以下两种方法。

a . 一次封锁法

一次封锁法要求每个事物必须一次将所有要使用的数据全部加锁,否则就不能继续执行。一次封锁法虽然可以有效地防止死锁的发生,但也存在问题。

第一,一次就将以后要用到的全部数据加锁,势必扩大了封锁的范围,从而降低了系统的并发度;

第二,数据库中的数据是不断变化的,原来不要求封锁的数据在执行过程中可能会变成封锁对象,所以很难事先精确地确定每个事务所要封锁的数据对象,为此只能扩大封锁范围,将事务在执行过程中可能封锁的数据对象全部封锁,这就进一步降低了并发度。

b . 顺序封锁法

顺序封锁法是预先对数据规定一个封锁顺序,所有事务都按这个顺序实行封锁。顺序封锁法可以有效地防止死锁,但同样存在问题。

第一,数据库系统中封锁的数据对象极多,并且随数据的插入,删除等操作而不断地变化,要维护这样的资源的封锁顺序非常困难,成本很高。

第二,事务的封锁请求可以随着事务的执行而动态地决定,很难事先确定每一个事务要封锁那些对象,因此也就很难按规定的顺序去施加封锁。



死锁的诊断与解除

数据库系统中诊断死锁的方法与操作系统相似,一般使用超时法或事务等待图法。

a . 超时法

如果一个事务的等待时间超过了规定的时限,就认为发生了死锁。超时法实现简单,但其不足也很明显。

第一,可能误判死锁,事务因为其他原因使等待时间超过了时限,系统会误认为发生了死锁。

第二,时限若设置得太长,死锁发生后不能及时发现。

b . 等待图法

事务等待图是一个有向图的G=(T,U)。T为结点的集合,每个结点表示正运行的事务;U为边的集合,每条边表示事务等待的情况。若T1等待T2,则T1,T2之间画一条有向边,从T1指向T2。如图(a)所示。

 事务等待图动态地反映了所有事务的等待情况。并发控制子系统周期性地(比如每隔数秒)生成事务等待图,并进行检测。如果发现图中存在回路,则表示系统中出现了死锁。

图(a)表示事务T1等待T2,T2又等待T1,产生了死锁。图(b)表示事务T1等待T2,T2等待T3,T3等待T4,T4又等待T1,产生了死锁。

当然,死锁的情况可以多种多样。例如图(b)中事务T3可能还在等待T2,在大的回路中又有小的回路。

数据库管理系统的并发控制子系统一旦检测到系统中存在死锁,就要设法去解除。通常采用的方法是选择一个死锁代价小的事务,将其撤销,释放此事务持有的所有锁,使其他事务得以继续运行下去。当然,对撤销的事务所执行的数据修改操作必须加以恢复

5. 并发调度的可行性

(1) 可串行化调度

多个事务的并发执行是正确的,当且仅当其数据结果与按某一次次序串行地执行这些事务时的结果相同,称这种调度策略为可串行化调度。可串行性是并发事务正确调度的准则。

(2) 冲突可串行化调度

  • 冲突操作

冲突操作是指不同的事务对同一个数据的读写操作与写写操作,其他操作是不冲突操作。不同事务的冲突操作和同一事物的两个操作是不能交换的。

  • 冲突可串行调度

一个调度Sc在保证冲突操作的次序不变的情况下F,通过交换两个事务的不冲突操作的次序得到另一个调度Sc',如果Sc'是串行的,称调度SC为冲突可串行化的调度。若一个调度是冲突可串行化,则一定是可串行化的调度。

6. 两段锁协议

为了保证并发调度的正确性,DBMS的并发控制机制必须提供一定的手段来保证调度是可串行化的。目前DBMS普遍采用两段锁协议的方法实现并发调度的可串行性,从而保证调度的正确性。

(1) 定义

两段锁协议是指所有事务必须分两个阶段对数据项加锁和解锁:在对任何数据进行读,写操作之前,首先要申请并获得对该数据的封锁;在释放一个封锁之后,事务不再申请和获得任何其他封锁。“两段”锁的含义是,事务分为两个阶段。第一阶段是获得封锁;第二阶段是释放封锁。

(2) 两段锁协议和一次封锁法的异同点

  • 相同点

一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行,因此一次封锁法遵守两段锁协议。

  • 不同点

两段锁协议并不要求事务必须一次性将所有要使用的数据全部加锁,遵守两段锁协议的事务可能发生死锁。

7. 封锁的粒度

(1) 封锁粒度

封锁对象的大小称为封锁粒度。封锁对象可以是逻辑单元,也可以是物理单元。

(2) 多粒度封锁

a . 结构

多粒度树:多粒度树的根节点是整个数据库,表示最大的数据粒度。叶节点表示最小的数据粒度。下图定义了一个三级多粒度树。

 b . 显式封锁和隐式封锁
多粒度封锁协议允许多粒度树种的每个节点被独立地加锁。对一个结点加锁意味着这个结点的所有后裔结点也被加以同样类型的锁。因此,在多粒度封锁中一个数据对可能一两种方式加锁,显示封锁和隐式封锁。

  • 显式封锁

显示封锁是应事务的要求直接加到数据对象上的封锁;

  • 隐式封锁

隐式封锁是该数据对象没有独立加锁,是由于其上级结点加锁而使该数据对象加上了锁。

c . 检查封锁方法
① 对某个数据对象加锁,系统要检查该数据对象是哪个有误显示封锁与之冲突;

② 检查其所有上级结点,看本事务的显示封锁是否与该数据对象上的隐式封锁冲突;

③ 检查所有下级结点,看上面的显示封锁是否与本事务的隐式封锁冲突。

(3) 意向锁

如果对一个结点加意向锁,则说明该节点的下层结点站在被加锁;对一个结点加锁时,必须先对它的上层结点加意向锁。三种常用的意向锁包括意向共享锁;意向排它锁;共享意向排它锁。

a . IS锁

如果对一个数据对象加IS锁,表示它的后裔结点拟加S锁。

b . IX锁

如果对一个数据对象加IX锁,表示它的后裔结点拟加X锁。

c . SIX锁

如果对一个数据对象加SIX锁,表示对它加S锁,再加IX锁,即SIX=S+IX。

8. 其他并发控制机制

(1) 时间戳方法

时间戳方法给每一个事务盖上一个时标,即事务开始执行的时间。每个事务具有唯一的时间戳,并按照这个时间戳来解决事务的冲突操作。如果发生冲突操作,就回滚具有较早时间戳的事务,以保证其他事务的正常执行,被回滚的事务被赋予新的时间戳并从头开始执行。

(2) 乐观控制法

乐观控制法认为事务执行时很少发生冲突,因此不对事务进行特殊的管制,而是让它自由执行,事务提交前再进行正确性检查。如果检查后发现该事务执行中出现过冲突并影响了可串行性,则拒绝提交并回滚该事务。乐观控制法又被称为验证方法。

(3) 多版本控制

多版本并发控制是指在数据库中通过维护数据对象的多个版本信息来实现高效并发控制的策略。

;