1、第十一章 并发控制,并发控制概述,多用户数据库系统。 多个用户并发地存取数据库时会产生多个事务同时存取同一数据的情况。 数据库管理系统必须提供并发控制机制。 并发控制机制是衡量一个数据库管理系统性能的重要标志之一。,例子,考虑飞机订票系统中的一个活动序列: 1.甲售票点(甲事务)读出某航班的机票余额A,设A=16. 2.乙售票点(乙事务)读出同一航班的机票余额A,也为16. 3.甲售票点卖出一张机票,修改余额AA-1.所以A为15,把A写回数据库. 4.乙售票点也卖出一张机票,修改余额AA-1.所以A为15,把A写回数据库. 结果明明卖出两张机票,数据库中机票余额只减少1。,三类不一致性,并发
2、操作带来的数据不一致性包括三类: 1)丢失修改、 2)不可重复读 3)读“脏”数据,丢失修改,两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了T1提交的结果,导致T1的修改被丢失。,不可重复读,不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。不可重复读包括三种情况: 事务T1读取某一数据后,事务T2对其做了修改,当事务1再次读该数据时,得到与前一次不同的值。事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神密地消失了。 事务T1按一定条件从数据库中读取某些数据记录后,事务T
3、2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。,读“脏”数据,读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤消,这时T1已修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一致,则T2读到的数据就为“脏“数据,即不正确的数据。,原因及解决,产生上述三类数据不一致性的主要原因是并发操作破坏了事务的隔离性。 并发控制就是要用正确的方式调度并发操作,使一个用户事务的执行不受其它事务的干扰,从而避免造成数据的不一致性。 交叉并发方式 同时并发方式 并发控制的主要技术是封锁(Locking)。,封锁,所谓封锁就是事务T在对某
4、个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。 基本的封锁类型有两种: 排它锁(Exclusive locks 简记为X锁) 和 共享锁(Share locks 简记为S锁).,排它锁,排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能再读取和修改A。,共享锁,共享锁又称为读锁。若事务T对数据对象A加上S锁,则事务可以T读A但不能修改A,其它事务只能再对A加S锁
5、,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。,T2T1 X S X N N Y S N Y Y Y Y Y,Y=Yes,相容的请求; N=No,不相容的请求,封锁类型的相容矩阵,封锁协议,对数据对象加锁时,还需要约定一些规则,称这些规则为封锁协议。 三级封锁协议,一级封锁协议,一级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 一级封锁协议可防止丢失修改,并保证事务T是可恢复的。 在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不
6、需要加锁的,所以它不能保证可重复读和不读“脏”数据。,二级封锁协议,二级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。 二级封锁协议除防止了丢失修改,还可进一步防止读“脏”数据。,三级封锁协议,三级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。 三级封锁协议除防止了丢失修改和不读脏数据外,还进一步防止了不可重复读,T1 T2 T1 T2 T1 T2 (1)获得 (1)SL A (1)获得 XL C XL A SL B 读C=200 (2)读A=16 读A,B C C2 请求 求和=150 请求 写回C=200
7、XL A (2) XL B (2) 请求 等待 等待 SL C (3)AA-1 等待 等待 等待 写回A=15 等待 (3)读A,B 等待 (3)ROLLBACK 等待 Commit 等待 求和=150 等待 (C恢复为100) 等待 Unlock X 等待 commit 等待 Ulock C 等待 (4) 获得 Ulock A 等待 (4) 获得 XL A Ulock B 等待 SL C读A=15 (4) X lockB 读c=100 (5) AA-1 读B=100 (5) Commit写回A=14 B B2 Unlock CCommit 写回B=200 Unlock X,(a)没有丢失修改
8、 (b)可重复读 (c)不再读“脏”数据,不同级别的封锁协议,活锁和死锁,和操作系统一样,封锁的方法可能引起活锁和死锁。,活锁,如果事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍然等待。然后T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求,.,T2有可能永远等待,这就是活锁的情形。 避免活锁的简单方法是采用先来先服务的策略。,死锁,如果事务T1封锁了数据R1,T2封锁了数据R2,然后T1又请求封锁R2,因T2已封锁了R2,于是T1等待T2释放R2上的锁。接着T2又申请封锁R1,因T1已封锁
9、了R1,T2也只能等待T1释放R1上的锁。这样就出现了T1在等待T2,而T2又在等待T1的局面,T1和T2两个事务永远不能结束,形成死锁。,产生死锁的原因,在数据库中,产生死锁的原因是两个或多个事务都已封锁了一些数据对象,然后又都请求对已为其他事务封锁的数据对象加锁,从而出现死等待。,死锁的预防,防止死锁的发生其实就是要破坏产生死锁的条件。预防死锁通常有两种方法:一次封锁法顺序封锁法,一次封锁法,一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行。 一次封锁法虽然可以有效地防止死锁的发生,但也存在问题,一次就将以后要用到的全部数据加锁,势必扩大了封锁的范围,从而降低了
10、系统的并发度。,顺序封锁法,顺序封锁法是预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁。 顺序封锁法可以有效地防止死锁,但也同样存在问题。事务的封锁请求可以随着事务的执行而动态地决定,很难事先确定每一个事务要封锁哪些对象,因此也就很难按规定的顺序去施加封锁。,死锁的诊断,超时法 等待图法,超时法,如果一个事务的等待时间超过了规定的时限,就认为发生了死锁。 超时法实现简单,但其不足也很明显。一是有可能误判死锁,事务因为其他原因使等待时间超过时限,系统会误认为发生了死锁。二是时限若设置得太长,死锁发生后不能及时发现。,等待图法,事务等待图是一个有向图G=(T,U)。 T为结点的集合,
11、每个结点表示正运行的事务;U为边的集合,每条边表示事务等待的情况。若T1等待T2,则T1、T2之间划一条有向边,从T1指向T2。事务等待图动态地反映了所有事务的等待情况。 并发控制子系统周期性地(比如每隔1分钟)检测事务等待图,如果发现图中存在回路,则表示系统中出现了死锁。,解除死锁,解除死锁通常采用的方法是选择一个处理死锁代价最小的事务,将其撤消,释放此事务持有的所有的锁,使其它事务得以继续运行下去。当然,对撤消的事务所执行的数据修改操作必须加以恢复,并发调度的可串行性,可串行化的调度:多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同。 正确调度:一个给定的并
12、发调度,当且仅当它是可串行化的。,T1 T2 T1 T2 Slock B Slock AY=B=2 X=A=2Unlock B Unlock A X lock A Xlock B A=Y+1 B=X+1 写回A(=3) 写回B(=3)Unlock A Unlock B Slock A Slock B X=A=3 Y=B=3 Unlock A Unlock B X lock B Xlock A B=X+1 A=Y+1 写回B(=4) 写回 A(=4) Unlock B Unlock,(a)串行调度 (b)串行调度,并行事务的不同调度,T1 T2 T1 T2S lock B S lock BY=B
13、=2 Y=B=2S lock A Unlock B X=A=2 X lock A Unlock B S lock A Unlock A A=Y+1 等待X lock A 写回A(=3) 等待A=Y+1 Unlock A 等待写回A(=3) X=A=3X lock B Unlock A B=X+1 X lock B 写回B(=3) B=X+1Unlock A 写回B(=4) Unlock B Unlock B,(c)不可串行化的调度 (d)可串行化的调度,并行事务的不同调度(续),保证调度可串行化的手段,为了保证并发操作的正确性,DBMS的并发控制机制必须提供一定的手段来保证调度是可串行化的。
14、目前DBMS普遍采用封锁方法实现并发操作调度的可串行性,从而保证调度的正确性。 两段锁(Two-Phase Locking,简称2PL)协议就是保证并发调度可串行性的封锁协议。 除此之外还有其他一些方法,如时标方法、乐观方法等来保证调度的正确性。,两段锁协议,所谓两段锁协议是指所有事务必须分两个阶段对数据项加锁和解锁: 1. 在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁,而且: 2. 在释放一个封锁之后,事务不再申请和获得任何其他封锁。 若并发执行的所有事务均遵守两段锁协议,则对这些事务的任何并发调度策略都是可串行化的,解释,所谓“两段”锁的含义是,事务分为两个阶段,第一阶段
15、是获得封锁,也称为扩展阶段。这在阶段,事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁。第二阶段是释放封锁,也称为收缩阶段。在这阶段,事务可以释放任何数据项上的任何类型的锁,但是不能再申请任何锁。,两段锁协议和一次封锁法异同,一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行,因此一次封锁法遵守两段锁协议; 但是两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务可能发生死锁。,封锁的粒度,封锁的对象的大小称为封锁粒度(Granularity)。封锁的对象可以是逻辑单元,也可以是物理单元。以关系数据库为例,封锁对象可以是这样
16、一些逻辑单元:属性值、属性值的集合、元组、关系、索引项、整个索引直至整个数据库;也可以是这样一些物理单元:页(数据页或索引页)、块等. 封锁粒度与系统的并发度和并发控制的开销密切相关。直观地看,封锁的粒度越大,数据库所能够封锁的数据单元就越少,并发度就越小,系统开销也越小;反之,封锁的粒度越小,并发度较高,但系统开销也就越大。,多粒度封锁,如果在一个系统中同时支持多种封锁粒度供不同的事务选择,这种封锁方法称为多粒度封锁(multiple granularity locking)。,多粒度树,显式封锁和隐式封锁,显式封锁是应事务的要求直接加到数据对象上的封锁;隐式封锁是该数据对象没有独立加锁,是
17、由于其上级结点加锁而使该数据对象加上了锁。,意向锁,意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。 于是,事务T要对关系R1加X锁时,系统只要检查根结点数据库和关系R1是否已加了不相容的锁,而不再需要搜索和检查R1中的每一个元组是否加了X锁。 三种常用的意向锁:意向共享锁(intent share lock),简记为IS锁,意向排它锁(intent exclusive lock),简记为IX锁,共享意向排它锁(share intent exclusive lock),简记为SIX锁。,IS锁,如果对一个数据对象加IS锁,
18、表示它的后裔结点拟(意向)加S锁。例如,要对某个元组加S锁,则要首先对关系和数据库加IS锁。,IX锁,如果对一个数据对象加IX锁,表示它的后裔结点拟(意向)加X锁。例如,要对某个元组加X锁,则要首先对关系和数据库加IX锁。,SIX锁,如果对一个数据对象加SIX锁,表示对它加S锁,再加IX锁,即SIX = S + IX。例如对某个表加SIX锁,则表示该事务要读整个表(所以要对该表加S锁),同时会更新个别元组(所以要对该表加IX锁),锁的相容矩阵,MS SQL Server 的并发控制,1. 锁的粒度2. 锁的模式3. 并发控制封锁方法4. 一些建议,MS SQL Server 锁的粒度,SQL
19、Server 2000具有多粒度锁定,允许一个事务锁定不同类型的资源。SQL Server可以锁定行、页、扩展盘区、表、库等资源。锁定粒度小(行)可增加并发,但需要较大的开销,锁定粒度大的就限制其他事务的访问。 行:是可以锁定的最小空间,占用的数据资源最少,允许其他事务继续操纵同一表的其他数据,提高了系统的并发性。,MS SQL Server 锁的粒度,页级锁:无论事务处理数据的多少,每次都锁定一页,这个页上的数据不能被其他事务操纵。SQL server 2000默认使用的是页级锁,页大小为8k, 每兆字节有128页。 表级锁:事务操纵某一表的数据时,锁定这个数据所在的整个表,其他事务不能访问
20、这个表中其他数据。特点:用比较少的系统资源,但占用比较多的数据资源。,MS SQL Server 锁的粒度,扩展盘区锁:是一种特殊的锁。在创建数据库和创建表时,系统分配物理空间时使用这种类型锁。当系统分配完空间后,就不再使用这种类型的盘区锁,涉及数据操作的事务时,不使用盘区锁。 库锁:锁定整个数据库,防止任何用户或事务对锁定的数据库访问。用于数据库恢复操作中。,MS SQL Server 锁的模式,共享锁:用于所有的只读数据操作,是非独占的 更新锁:在修改操作初始化阶段用来锁定可能要修改的资源 排它锁:写锁 结构锁:执行表的数据定义语言(DDL)操作时使用结构锁 意向锁:说明有向资源的低层获得
21、共享锁或排它锁的意向 大容量更新锁:向表中大容量复制数据时使用,MS SQL Server 的封锁方法,DBMS普遍采用封锁方法有:悲观方法、乐观方法和时标方法 悲观并发控制:锁定系统阻止用户以影响其它用户的方式修改数据。如果用户执行的操作导致应用了某个锁,则直到这个锁的所有者释放该锁,其它用户才能执行与该锁冲突的操作。该方法主要用在数据争夺激烈的环境中,以及出现并发冲突时用锁保护数据的成本比回滚事务的成本低的环境中,因此称该方法为悲观并发控制。 SQL Server采用的是这种封锁方法。,MS SQL Server 的封锁方法,DBMS普遍采用封锁方法有:悲观方法、乐观方法和时标方法 乐观并
22、发控制:在乐观并发控制中,用户读数据时不锁定数据。在执行更新时,系统进行检查,查看另一个用户读过数据后是否更改了数据。如果另一个用户更新了数据,将产生一个错误。一般情况下,接收错误信息的用户将回滚事务并重新开始。该方法主要用在数据争夺少的环境内,以及偶尔回滚事务的成本超过读数据时锁定数据的成本的环境内,因此称该方法为乐观并发控制。,MS SQL Server 的封锁方法,DBMS普遍采用封锁方法有:悲观方法、乐观方法和时标方法 时标并发控制:时标和封锁技术之间的基本区别是封锁是使一组事务的并发执行(即交叉执行)同步,使用它等价于这些事务的某一串行操作;时标法也是使用一组事务的交叉执行同步,但是
23、使它等价于这些事务的一个特定的串行执行,即由时标的时序所确定的一个执行。如果发生冲突,是通过撤销并重新启动一个事务解决的。事务重新启动,则赋予新的时标。,一些建议,SQL Server系统建议由系统自动管理锁。系统会定期搜索和处理死锁问题。 应用程序可采用下面方法来尽量避免死锁: 1) 合理安排表访问顺序 2) 事务中尽量避免用户干预,尽量让事务处理的任务少些 3) 数据存储空间离散法,如将一个大表分解成多个小表 4) 使用尽可能低的隔离性级别,小 结,要求:掌握为什么要进行并发控制、并发控制的基本技术:封锁。了解封锁协议、并发调度的可串行性、两段封锁协议。结合实际数据库系统介绍并发控制的方法。,