基于封锁的事务并发控制概述发表时间:2010-05-14T10:46:24.013Z 来源:《计算机光盘软件与应用》2010年第4期供稿作者:卢成浪,徐湖鹏[导读] 叙述了关系型数据库管理系统中的事务管理和基于锁的事务并发控制方法。
卢成浪,徐湖鹏(温州大学瓯江学院,温州 325035)摘要:叙述了关系型数据库管理系统中的事务管理和基于锁的事务并发控制方法。
详细介绍了事务的串行化调度方法中的锁技术和锁协议,并深入讨论了锁的管理、死锁处理、幻影问题和其它加锁过程中可能出现的一些问题。
关键词:数据库管理系统;事务;并发控制;封锁中图分类号:TP311.131 文献标识码:A 文章编号:1007-9599 (2010) 04-0000-03Lock-Based Transaction Concurrency Control OverviewLu Chenglang,Xu Hupeng(Wenzhou University,Oujiang College,Wenzhou 325035,China)Abstract:An overview on the management of lock-based concurrency control of transactions is presented in this paper.The locking protocols and locking techniques of the locking are discussed in depth.Keywords:Database management systems;Transaction;Concurrency control;Lock一、引言事务是用户定义的一组数据库操作序列。
事务的执行结果将使数据库从一个一致性状态转变到另一个一致性状态。
为了提高吞吐量,系统中常常是多个事务并发执行。
这会产生多个事务同时存取同一数据的情况,从而破坏数据库的一致性。
所以数据库管理系统(Database Management System,DBMS)必须提供并发控制机制,使得并发的事务在冲突的时候被串行化执行。
这种调度称为可串行化调度。
其中基于封锁的并发控制机制是一种被广泛应用于商业DBMS中的并发控制机制。
二、事务的特性和并发的数据不一致性事务具有ACID特性:原子性(Atomicity),一致性(Consistency),隔离性(Isolation)和持续性(Durability)。
原子性指:事务包含的所有操作要么全部被执行,要么都不被执行;一致性指:事务的执行结果必须使数据库从一个一致性状态变到另一个一致性状态;隔离性指:在事务被提交以前,其操作结果对于其他事务不可见;持续性指:一旦事务成功提交,其对数据库中数据的改变是永久的。
事务是并发控制的基本单位,保证事务的ACID特性是事务处理的重要任务。
然而,事务的并发执行可能会破坏事务的ACID特性,而导致数据的不一致性:(一)Write-Write冲突,丢失更新。
它是由于事务之间的写冲突造成的。
两个事务T1和T2同时读入同一数据并修改,T2的提交破坏了T1的提交结果,导致T1的修改丢失。
(二)Read-Write冲突,也称不一致读。
不一致读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。
它包括三种情况:1.T1读取某一数据后, T2对其做了修改,当T1再次读取该数据时,得到与前一次不同的值;2.T1按一定的条件从数据库中读取了某些记录后,T2删除其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神秘的消失了;3.T1按一定的条件从数据库中读取了某些记录后,T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。
后两种情况也称幻影现象。
(三)Write-Read冲突,也称读脏数据。
读脏数据指事务T1修改某数据,事务T2读取同一数据后,T1由于某种原因被撤销,这时T1已修改过的数据恢复原值,T2读到的数据就与数据中的数据不一致,则称T2读到的数据就为脏数据。
三、基于封锁的事务并发控制机制(一)锁的类型封锁是实现并发控制的一个非常重要的技术。
所谓封锁就是事务T在对某个数据对象例如表,记录等操作之前,先向系统发出请求,对其加锁。
加锁后事务T就对该数据对象有了一定的控制,在事务T释放它之前,其他事务不能更新该数据对象。
下面介绍DBMS涉及的锁:1.互斥锁(Exclusive Lock):用于写操作,又称写锁或者排他锁,记做X锁。
若事务T对数据对象A加上X锁,则只允许T读写A,其他事务都不能对A加任何锁,直到T释放A上的锁。
2.共享锁(Shared Lock):用于读操作,又称读锁,记做S锁。
若事务T对数据对象A加上S锁,则T可读A但不能写A,其他事务只能对A加S锁,而不能加X锁,直到T释放锁。
3.更新锁(Update Lock):用于更新操作。
等价于先加共享锁,在真正执行更新操作时,将共享锁升级为互斥锁。
大部分DMBS 都不使用这种锁。
4.增量锁(Increment Lock):用于增量操作,如果一个对象被上了增量锁,除增量操作以外任何读写操作都是被禁止的。
即增量锁之间不排斥。
因同时对某一对象的数值进行加一或者减一操作时,其结果与操作先后顺序是无关的,可以交换。
这种锁使用并不广泛。
5.意向锁(Intention Lock):它是因为引入多粒度对象而产生的,又可细分为:意向共享锁,意向排他锁和共享意向排他锁。
在DBMS 中被广泛使用的是共享锁,互斥锁和意向锁。
为了保证写操作的互斥性,不同事务对同一数据对象加锁时需要进行冲突检测。
检测可以借助锁的相容矩阵来判断,如图1(a)所示。
从中可以发现5种锁的强度偏序关系,如图1(b)所示。
(二)加锁管理和锁转换DBMS中处理事务加锁事宜的部分被称为锁管理器。
锁管理器维护着一个锁表,这是一个以数据对象标志为码的哈希表。
DBMS也在事务表中维护着每个事务的描述信息项,该记录中包含一个指向事务拥有的锁列表的指针。
在请求锁之前要检查这个列表,以确定不会对同一个锁请求两次。
加锁表中的每一项针对某个数据对象(可以是一页,一条记录等等),它包括下面的信息:拥有数据对象锁的事务数目,锁的属性(共享锁、互斥锁等)和一个指向加锁请求队列的指针。
1.加锁和解锁请求的实现。
当事务需要某个对象的锁时,需要将请求提交给锁管理器。
如果请求的是共享锁,当前请求队列为空,而且该对象没有处于互斥锁状态时,锁管理器就将同一加锁请求,并更新该对象的相应的锁表数据项。
如果请求的是互斥锁,并且没有事务拥有该对象的锁,那么锁管理器可以同意加锁请求,并更新该对象的相应锁表数据项。
对于其它情况,加锁请求不能立刻得到满足,加锁请求将被添加到该对象的加锁请求队列中,同时挂起请求加锁的事务。
当事务中止或者提交时,会释放自己拥有的锁。
当某个对象被释放时,锁管理器更新相应锁表数据项,并检查该对象的加锁请求队列。
如果请求能被接受,请求锁的事务将被唤醒并得到锁。
其中,加锁和解锁操作必须是原子操作。
为确保这两个操作的原子性,锁管理器需要使用操作系统的同步机制来小心的访问锁表。
2.锁转换。
事务可能需要对已经获得了共享锁的对象再请求排他锁。
此时,如果没有其他事务拥有该对象的共享锁,可以立即对事务的锁进行升级满足互斥锁请求,否则将该加锁请求加到等待队列的最前面。
但是,使用锁的升级不能避免由冲突更新操作导致的死锁。
例如,如果两个事务已经获得了一个对象的共享锁,又请求排他锁,就会导致死锁。
一个更好的法子是不进行锁升级,而是在开始时首先获得排他锁,当知道只需要共享锁就足够了时,再对锁降级。
但该方法又将会导致在某型情况下事务并需要排他锁时,降低了系统的并发度。
但是从整体来讲,它通过减少死锁改善了吞吐量。
因此该方法在目前的商用DBMS中被广泛使用。
并发度的问题可以通过引入前面提到的更新锁来改善。
在事务开始时申请更新锁而不是排他锁,就可以防止与读操作的冲突。
一旦确定不要对对象进行更新,就可以将锁降级为共享锁。
如果需要更新对象,则可以将锁升级为排他锁。
3.并发调度的可串行性和两段锁协议。
计算机系统对并发事务中并发操作的调度是随机的,而不同的调度可能会产生不同的结果。
其正确性的评判标准是:并发调度的可串行性。
即多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行的执行它们时的结果相同。
两段锁(Two Phase Locking,简称2PL)协议就是保证并发调度可串行性的封锁协议。
所谓“两段”的含义是,事务分为两个阶段,第一阶段是获得封锁,也成为扩张阶段。
在该阶段,事务可以申请获得任何数据项上的任何类型的锁,但不能释放任何锁。
第二阶段是释放锁,也成为收缩阶段。
在该阶段,事务可以释放其拥有的数据项上的任何类型的锁,但是不能再申请任何锁。
但是由于一个事务是由若干操作组成的,因此在实际执行过程中,很难判断一个事务还会不会再提出锁请求。
一种比较实用的方案就是:事务将一直保持它在执行过程中获得的所有的锁,直到该事务被提交或者撤销时才释放它们。
两阶段锁协议的工作流程可概括为:开始事务;在读数据前获得共享锁,在写操作前获得互斥锁,并在获取锁时进行锁的冲突检测;进行读/写操作;释放事务拥有的共享锁;结束事务(提交或者撤销);释放所有的本事务所持有的互斥锁。
4、封锁的粒度。
封锁对象的大小称为粒度。
目前,在商用DBMS中,最小锁定对象是记录,最大对象是表。
锁定的对象可以是一张数据表,一个页面或一条记录,甚至是一条记录中的某个字段。
封锁粒度与系统的并发度和并发控制的开销密切相关。
封锁的粒度越大,数据所能够封锁的数据单元就越少,并发度就越小,系统开销也越小;反之,封锁的粒度越小,并发度越高,系统开销也越大。
因此,如果在一个系统中同时支持多种封锁力度是比较理想的,这种封锁方法称为多粒度锁。
多粒度锁虽然灵活,但也带来了一个新的问题:具有隶属关系的锁定对象如何检测到对方的存在。
比如对于一个被上了表级写锁的数据表,尽管该表中的记录并没有被显示加锁,但应禁止对其包含的记录进行读写。
反之,对已经加了记录级写锁的记录,也不能对它所属的表再加读锁。
为此人们引入了意向锁来解决这个问题。
意向锁的含义是如果对一个对象上意向锁,则说明它的某个下一级对象要被加锁。
显然,要对小粒度对象上锁,必须先对其所属的上级对象加意向锁;要释放小粒度对象的锁,必须先释放本身,然后释放其上层对象的意向锁。
意向锁有三类:IS,IX 和SIX。
如果对一个数据对象加IS锁,表示它的下一级对象拟加S锁,比如想对某记录上读锁,那么就需先对其所属的表加IS锁,然后再对指定记录加读锁;如果对一个数据对象加IX锁,表示它的下一级对象拟加X锁;如果要对一个数据对象加SIX锁,表示对它加S锁,再加IX锁。