封锁就是事务T在对某个数据对象操作之前,先向系统发出请求,对其加锁.加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象.
1. 封锁类型
基本的封锁类型有两种:排它锁(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锁,而不能加X锁,直到T释放A上的S锁.这就保证了其它事务可以读A,但在T释放A上的S锁之前其它事务不能对A做任何修改.
排它锁与共享锁的相容矩阵如下:
T1 T2
X
S
-
X
N
N
Y
S
N
Y
Y
-
Y
Y
Y
2. 封锁协议
在运用X锁和S锁这两种基本封锁,对数据对象加锁时,还需要约定一些规则,例如应何时申请X锁或S锁,持锁时间,何时释放等,我们称这些规则为封锁协议(Locking Protocol).对封锁方式规定不同的规则,就形成了各种不同的封锁协议.下面介绍三级封锁协议.对并发事物的不正确调度可能会带来丢失修改,不可重复读和读"脏"数据等不一致性问题,三级封锁协议分别在不同程度上解决了这些问题,为并发事物的正确调度提供一定的保证.不同级别的封锁协议使系统一致性达到的级别是不同的,而两段锁协议是为了保证并发事务的可串行性(Serializability).
(1) 一级封锁协议
一级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放.事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK).一级封锁协议可防止丢失修改,并保证事务T是可恢复的.
顺序
事务T1
事务T2
①
Xlock A
②
读A=20
Xlock A
③
写A=19
等待
④
COMMIT
等待
⑤
UnXlock A
获取 Xlock A
⑥
读A=19
⑦
写A=18
⑧
UnXlock A
⑨
其它操作
⑩
COMMIT
在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证不读"脏"数据和可重复读.
(2) 二级封锁协议
二级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁.二级封锁协议除防止了丢失修改,还可进一步防止读"脏"数据.由于读完后即可释放S锁,所以不能保证可重复读.
顺序
事务T1
事务T2
①
Xlock A
②
读A=10
Slock A
③
写A=5
等待
S④
ROLLBACK(A=10)
等待
⑤
UnXlock A
获取Slock A
⑥
读A=10
⑦
UnSLock A
⑧
COMMIT
(3) 三级封锁协议
三级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放.三级封锁协议除防止了丢失修改和不读'脏'数据外,还进一步防止了不可重复读.
顺序
事务T1
事务T2
①
Slock A
②
读A=10
Xlock A
③
读A=10(验证)
等待
④
COMMIT
等待
⑤
UnSlock A
获取Xlock A
⑥
读A=10
⑦
写A=5
⑧
COMMIT
⑨
UnXlock A
(4) 两段锁协议
两段锁协议(Two-Phase Locking,简称2PL),是指所有事务必须分两个阶段对数据项加锁和解锁.在对任何数据进行读,写操作之前,首先要申请并获得对该数据的封锁,在释放一个封锁之后,事务不再申请和获得任何其他封锁.
所谓"两段"锁的含义是,事务分为两个阶段,第一阶段是获得封锁,也称为扩展阶段.在这阶段,事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁.第二阶段是释放封锁,也称为收缩阶段.在这阶段,事务可以释放任何数据项上的任何类型的锁,但不能再申请任何锁.
例如事务T1遵守两段锁协议,其封锁,解锁序列:
例如事务T2不遵守两段锁协议,其封锁,解锁序列:
Slock A UnSlock A Slock B Xlock C UnXlock C UnSlock B;
可以证明,若并发执行的所有事务均遵守两段锁协议,则对这些事务的任何并发调度策略都是可串行化的.两阶段锁定义了事务如何获取和释放锁.两阶段锁定保证了可串行化,两个阶段分别是:
增长阶段:在增长阶段事务获得所需要的锁,但不释放任何数据上的锁.一旦所有的锁都已被获得了,事务就达到了它的锁定点.
缩减阶段:在缩减阶段事务释放所有的锁,但不能获得新锁.

