18143453325 在线咨询 在线咨询
18143453325 在线咨询
所在位置: 首页 > 营销资讯 > 信息时代 > 基于封锁的并发控制(数据库)

基于封锁的并发控制(数据库)

时间:2022-12-28 10:30:01 | 来源:信息时代

时间:2022-12-28 10:30:01 来源:信息时代

    基于封锁的并发控制 : 利用封锁机制(加锁和解锁)来控制多个事务的并发执行,以保证该多个事务并发执行的正确性。
封锁(locking),顾名思义就是对一个数据对象在一定时间一定强度的独占。事务在对某个数据对象(例如表、元组等)操作之前,向DBMS发出申请,对其加锁。在这个事务对该对象解锁之前,其他事务就不可以更新该对象。
利用封锁就可以强制地让那些竞争同一资源的事务之间形成等待关系,而让那些相互没有资源竞争关系的事务之间可以随意地执行。
根据对封锁对象的独占强度,封锁可以分为排他锁和共享锁。排他锁(exclusive lock)也称写锁或X锁,是指对资源的独占性封锁,当一个数据对象被加了排他锁后,其他事务就不能读或者更新该对象。有的时候,排他锁显得过于严格,不利于提高事务执行的并发度。比如,两个事务对同一个对象A都是读操作,并不修改这个对象,那么就没有必要相互阻塞,可以同时读取。将这样的锁称为共享锁(shared lock),也称读锁或S锁。当一个数据对象被加了共享锁后,允许其他事务读该数据对象,但是不允许修改。
读锁和写锁之间的关系可以用下面的相容矩阵来描述:

 X-LOCKS-LOCK
X-LOCKNN
S-LOCKNY


相容矩阵中的Y表示相容,也就是可以同时加于同一个数据对象上,而N表示不相容。
若一个事务对数据对象A加了X锁,那么只允许该事务对该数据对象进行读取和更新,其他任何事务都不能再对A加任何类型的锁,也不能进行任何类型的操作,直到事务释放了对A的锁。
若一个事务对数据对象A加了S锁,那么该事务可以读但是不能写A,其他事务只能再对A加S锁,而不能加X锁。这就保证了其他事务可以读A,但是不能修改。
封锁仅仅提供了一种调度并发事务的基本的手段,并不能解决调度的正确性问题,而且还会引起一些新的问题,包括死锁和活锁。
死锁(deadlock):是多个事务之间在竞争同一个共享对象的封锁时,形成一种相互等待的现象,造成事务的停滞。死锁的发生可能出现在多个事务同时运行时。
活锁(livelock): 一个事务长时间不能获得对某个对象的封锁,从而造成事实上的长时间停滞。这种情况也称饿死(starvation)。
假如有两个事务A和B,事务A已经拥有对数据对象O1的封锁,并等待对O2的封锁,而事务B相反,已经拥有对O2的封锁并在等待对O1的封锁。两者形成了相互等待的这样一种状态,事务执行被阻塞。这种状态称为死锁。假如有一个事务A在等待对数据对象O的封锁,有另一个事务B1目前拥有对O的封锁,在B1释放了对O的封锁后,由于某种原因,事务A没有获得对O的封锁,而是另一个新的事务B2获得了对O的封锁,如果这种状况一直持续下去,事务A总是不能获得对O的封锁,那么事务A形成了事实上的被阻塞,这种状态称为活锁。
死锁和活锁都会造成事务执行被阻塞,影响系统的正常运行,都是并发控制必须解决的问题。但是造成这些问题原因不在封锁本身,而是出在使用封锁的方式上。因此,什么样的封锁约定(协议)能够确保调度的正确性,合理解决死锁/活锁问题,同时又有高的性能是数据库并发控制部件最为关心的。
封锁协议(locking protocol)是关于系统如何运用封锁机制实现正确高效并发控制的约定。封锁协议要保证事务被正确执行,避免死锁发生,并具有满意的性能。这些要求中,保证正确性是最重要的,在保证正确性的前提下,如何提高系统的事务处理吞吐量也是一个重要的方面。下面的封锁协议能保证事务的正确执行,但执行效率不一定很高:
加锁规则1: 对修改的数据对象要加X锁,对只读的数据对象要加S锁,一个数据对象如果已经被加了锁,那么就不能再对其加其他不相容的锁。
持锁规则2: 事务一旦获得某个封锁就一直保持到事务结束。
解锁规则3: 事务不能对没有加锁的数据对象解锁,在事务结束的时候要释放其拥有的全部的锁。
影响最大的封锁协议是1976年由Eswaran提出的两阶段封锁协议(two-phase locking protocol,2PL)。它可以认为是对上述封锁协议中持锁协议规则的一个改进。
所有事务的执行都区分为加锁和解锁两个阶段: 在对任何数据进行读写操作之前,首先要申请并获得对该数据的相应的封锁。在释放了一个封锁之后,该事务不再申请和获得任何其他封锁。
已经证明了遵循2PL的调度是一种可串行化调度算法,因此2PL是正确的。但是,必须说明的是,2PL协议可能造成死锁。正确性和活锁/死锁是不同的两件事情,正确的调度也不能保证不出现死锁。反过来,不出现死锁的调度也不一定是正确的调度。
死锁预防也可以通过遵循一定的协议方式来避免。以下规则中的任何一条都可以用来作为死锁预防协议:
(1)预先资源申明规则: 在事务开始执行之前,要求预先申请到全部资源。
(2)预先资源排序规则: 预先对全部数据对象进行排序,任何事务都要求按照这个顺序对数据对象加锁。
(3)预先事务排序规则: 对竞争资源的事务进行排序,按照这个顺序进行执行。
(4)事务回滚规则: 一个事务在申请加锁时如果被拒绝,不是等待而是采取回滚的方式,将已经占有的资源退出来,重新启动该事务的执行。
需要说明的是,由于死锁发生的几率并不大,按照上述协议来执行,限制较多,影响了实际系统的效率,因此,在很多实际的数据库系统中并不采用协议这种方式来避免死锁,而是采用检测的方法发现死锁,然后采用其他补救措施,比如,取消处于死锁中的某个事务,然后再重新启动该事务的执行。
数据库的封锁对象可以是逻辑单元(如关系的属性值、元组、关系、索引项)也可以是物理单元(数据块)。这些对象有大有小,封锁对象的大小,直接影响到封锁的代价和并发度。一般而言,封锁的粒度越大,并发度就越小,同时所需要的锁资源就越少,封锁的代价就越小。反之,封锁粒度越小,并发度就越大,所需的锁资源就越多,封锁的代价就越大。因此,如果系统能够根据事务的特征,选择合适的封锁粒度,并且在必要时进行封锁粒度的转换,将是非常理想的。这种封锁方法称为多粒度封锁。
数据库中的对象,从数据库到关系再到元组形成一个自然的层次结构(树),这个层次结构以数据库为根结点,以元组为叶结点。这个层次结构称为多粒度树。
树中的每一个结点都可以被加锁,对一个结点加锁,意味着对这个结点的全部后代结点也加上了同样类型的锁。该结点上加的锁为显式封锁,而后代结点上的锁为隐式封锁。尽管有这种称呼上的区别,但是其效果是一样的。因此,系统在检查封锁之间的相容性的时候,不仅要检查显式封锁,还要检查隐式封锁。这样一来,给检查工作带来了很大的麻烦。当试图给某个数据对象加锁时,系统要检查这个数据对象上的所有显式封锁,还要检查其所有的祖先结点,看本结点的所有隐式封锁是否与拟加的锁冲突。不仅如此,还要检查其所有的下属结点上的显式封锁是否与拟加的封锁冲突。显然,这样的检查方法的效率是很低的。
为了解决上述问题,引进一种新的封锁类型,称为意向锁(intension lock)。当系统要对某一个数据对象加锁时,必须首先对该对象的上层结点加意向锁。有三种意向锁:
(1)意向共享锁(IS锁): 当某结点拟加S锁时,它的全部祖先结点要加IS锁。
(2)意向排他锁(IX锁):当某结点拟加X锁时,它的全部祖先结点要加IX锁。
(3)共享意向排他锁(SIX锁): 当一个对象加SIX锁时,表示对它既加S锁又加IX锁,即SIX=S+IX。
这些锁的相容矩阵如下:

 SXISIXSIX
SYNYNN
XNNNNN
ISYNYYY
IXNNYYN
SIXNNYNN


多粒度封锁协议提高了系统的并发度,同时减少了开销。它已经在实际的数据库产品中得到了广泛的应用。
封锁是通过一个锁表来实现的。一个锁表的记录就是某个数据库元素及与之相应的封锁信息。通常按照数据库元素来组织,每一个记录包括对该数据库元素施加了封锁的全部事务的封锁类型和状态等信息。

关键词:控制,数据

74
73
25
news

版权所有© 亿企邦 1997-2022 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭