一、引言
1、封锁技术是目前大多数商用DBMS采用的并发控制技术,封锁技术通过在数据库对象上维护锁来实现并发事务非串行调度的冲突可串行化
2、基于锁的并发控制的基本思想是:
当一个事务对需要访问的数据库对象,例如关系、元组等进行操作之前,要先向系统发出封锁请求,获得所访问的数据库对象上的锁,即对数据库对象进行加锁来限制并发的其他事务对这些数据对象的访问
3、DBMS采用的封锁模式均包括共享锁和排它锁,同时采用两阶段封锁协议来约定锁的使用,保证并发事务非串行调度的可串行化
二、封锁模式
由于事务对数据库对象的操作分为读操作和写操作,因此,常用的封锁模式中也有两种类型的锁,一种用于读,称作共享锁,简称S锁,又称作读锁
一种用于写,称作排他锁,简称X锁,又称作写锁
1、共享锁
(1)若事务T想读取数据库对象A而不更新A,事务T必须申请获得A上的共享锁
(2)若申请成功,则事务在数据库对象A上加共享锁,事务T可以读A但不能写A
(3)其他事务只能再对A加共享锁,而不能加排他锁
这就保证了其他事务可以读A,但在事务T释放A上的共享锁之前,不能对A作任何更新
2、排他锁
(1)若事务T不仅要读取数据库对象A还要更新A ,事务T必须申请获得A上的排他锁
(2)若申请成功,则事务T在数据库对象A上加排他锁,事务T不仅可以读A还能写A
(3)其他事务不能对A加任何类型的锁
这就保证了在事务T释放A上的排他锁之前,其它事务不能再读取和更新A
3、对于任何数据库对象A,其上只能有一个排他锁,或者没有排他锁而有多个共享锁,也就是有多个事务可以同时读取A,但只能有一个事务读取并更新A
4、为了使并发执行的事务提早执行或提前完成,提高事务的执行效率。如果一个事务T想要读数据库对象A并可能更新A,应首先申请A上的一个共享锁,获得A上的共享锁后,友好地对待其他事务,允许其他事务申请并获得A上的共享锁,同时读取A,而仅当事务T准备为A写入新值时,再申请将加在A上的共享锁升级为排他锁。而事务T的锁升级请求是否会得到满足,则要看此时数据库对象A上的加锁情况
5、在同一数据库对象上已经被某事务加锁的情况下,并发控制机制能否同意其他事务的封锁申请的策略,可用一个锁相容矩阵来描述
在锁相容矩阵中,最左边一列表示在某数据库对象上事务T1已经获得的锁,S为共享锁,X为排他锁,—表示没有加锁,最上边一行表示另一事务T2对该数据库对象发出的封锁请求,T2的封锁请求能否被满足,用矩阵中的Y和N来表示,Y即YES,表示T2申请的锁与T1已拥有的锁相容,封锁请求可以满足,N即NO,表示事务T2申请的锁与T1已持有的锁冲突,T2的封锁请求被拒绝
6、现在我们知道如何使用锁了,对于我们上一节所提到的这个非可串行化的调度,如果我们在调度中,当事务对需要访问的数据库对象进行操作之前,要先向系统发出封锁申请,在读之前申请读锁并获得锁,在写之前升级为写锁并获得锁,写完释放锁。
这里用Slock(A)表示在某数据对象A上加上共享锁,Xlock(A)表示在A上加上排他锁,Unlock(A)表示释放A上的锁,也称解锁。可以发现,虽然我们正确地进行了封锁操作,但并没有解决该并发事务的非可串行化问题
三、封锁协议
1、在利用封锁技术对并发事务进行操作时,需要对事务何时申请要访问的数据库对象上的锁,何时释放所获得的锁等约定一些规则,即封锁协议
2、约定不同的规则就形成了各种不同的封锁协议
3、两阶段封锁协议是最常用的一种实现可串行化的封锁协议
四、两阶段封锁协议
两阶段封锁协议对事务调度中的封锁操作的顺序进行限制,要求在每个事务中,所有的加锁操作优先于所有解锁操作,即每个事务在对数据库对象进行封锁时,必须分获得锁和释放锁两个阶段
1、第一阶段是获得锁阶段,也称扩展阶段
- 在这个阶段,事务要申请得到完成事务操作所需要的所有锁,只能申请锁,不能释放锁
2、第二阶段是释放锁阶段,也称收缩阶段
- 在这个阶段,事务释放所获得的所有锁,不能再申请任何锁
若事务遵循两阶段封锁协议,其封锁操作序列应类似这种形式
先是对需要访问的各数据对象加锁,然后再开始释放锁,实际应用中,为了便于阶段的划分,通常将释放锁阶段放在事务结束时的COMMIT或ROLLBACK操作中完成
因此许多DBMS的并发控制机制,采用严格的两阶段封锁协议来实现并发事务的可串行化
3、其协议规则包含如下具体内容
- 事务T在读一个数据库对象前,必须获得该数据库对象上的读锁,如果没有其他事务拥有这个数据库对象上的写锁,那么事务T的封锁请求得到满足,操作继续执行
- 事务T在更新一个数据库对象前,必须获得该数据库对象上的写锁,如果没有其他事务拥有这个数据库对象上的读锁或写锁,那么事务T的封锁请求得到满足,操作继续执行。若事务T已具有该数据库对象上的读锁,则必须将读锁升级为写锁,也必须获得该数据库对象上的写锁
- 若事务B的封锁请求与事务A已获得的锁不相容时,事务B将处于等待状态,直到事务A释放其所拥有的锁为止
- 事务所获得的锁将一直保持到事务结束才释放。即直到事务提交或终止且提交或终止日志记录已被刷新到磁盘后,事务才允许释放锁
这就是严格封锁协议的要求
3、前面我们对这个非串行化调度进行的封锁操作,并没有解决并发事务的非可串行化问题。若采用严格的两阶段封锁协议,事务T1在读取数据库对象X之前,申请并获得读锁,写数据库对象之前升级读锁为写锁,写后并没有释放锁,然后事务T2对数据库对象X申请的读锁,与事务T1已持有的数据库对象X上的写锁不相容,封锁请求得不到满足,事务T2处于等待状态,事务T1继续完成对数据库对象Y的读写,事务执行完成,提交后才释放数据库对象X和Y上的锁,事务T2才能够开始执行,事务T2在事务T1释放锁之前被拒绝执行,推迟了将导致非可串行化的操作的执行,调度的执行实际上相当于事务T1先于T2的一个串行调度,实现了并发事务的可串行化
4、对于我们在上一节讨论的并发事务带来的数据不一致问题,比如“脏读”问题,事务T1在完成之前发生了故障,需撤销回滚,事务T2读取了夭折事务T1对X的中间更新结果,是一个脏数据
若采用严格两阶段封锁协议进行并发控制,在事务T2因对数据库对象X申请的读锁与事务T1已持有的数据库对象上的写锁不相容而处于等待状态时,事务T1在完成之前发生了故障,则事务T1终止并撤销回滚,将X的值恢复为事务开始时的值,事务T1结束才释放所持有的数据对象X上的锁,事务T2才能够开始执行,此时事务T2读取的是夭折事务T1 ROLLBACK后的值,即事务T1没执行前的值,是数据库处于一致性状态时的值,不再是脏数据
五、小结
1、封锁技术通过共享锁间的相容性,以及排他锁的排他性,使得并发调度中的非冲突操作并发执行,冲突操作串行执行,实现了冲突可串行化
2、采用封锁技术进行并发控制的DBMS,在具体实现时使用的锁类型,除了共享锁和排他锁两种基本锁外,为了事务能够高效地并发执行并减少死锁的发生,还会使用一些其他类型的锁,形成相应的封锁策略及对应的锁相容矩阵,以及采用更能便于应用执行的封锁协议,而不一定是可串行化的严格的两阶段封锁协议