DBMS 中使用锁进行并发控制
锁是维护 DBMS 中并发控制不可或缺的一部分。在任何实现基于锁的并发控制的系统中,事务在获得所需的锁之前都不能读取或写入语句。
基于锁的协议中有两种类型的锁。它们是
- 二元锁 - 这些锁只能处于两种状态之一:锁定或解锁。
- 共享/排他锁 - 当仅执行读取操作时,会获取共享锁。多个事务可以共享共享锁,因为没有数据被更改。当执行写入操作时,使用排他锁。只有持有排他锁的事务才能更改数据值。
不同的锁定协议如下:
简单锁定协议
在执行写入操作之前,事务会在数据值上获得锁。写入操作完成后,可以释放锁。简单锁定协议的一个示例是
T1 | T2 |
---|---|
R(A) | |
R(A) | |
Lock(B) | |
R(B) | |
W(B) | |
Unlock(B) | |
Lock(C) | |
R(C) | |
W(C) | |
Unlock(C) | |
Commit | |
Commit |
上面显示了两个事务 T1 和 T2。读取操作不需要锁,但在写入操作之前,每个事务都会获取一个锁并在之后释放它。
两阶段锁定协议
两阶段锁定协议有两个阶段,即增长阶段和收缩阶段。事务只有在增长阶段才能获取锁。当它进入收缩阶段时,它可以释放之前获取的锁,但不能获取新的锁。排他锁由 X 表示,共享锁由 S 表示。两阶段锁定协议的一个示例如下:
T1 | T2 |
---|---|
S(A) | |
R(A) | |
S(A) | |
R(A) | |
X(B) | |
R(B) | |
W(B) | |
X(C) | |
R(C) | |
W(C) | |
Unlock(C) | |
Unlock(A) | |
Unlock(B) | |
Unlock(A) | |
Commit | |
Commit |
在上面的示例中,T1 和 T2 使用共享锁共享变量 A,因为仅对 A 执行读取操作。T1 获取对 B 的排他锁以进行写入操作,并在之后立即释放它。T2 对 C 执行相同的操作。
严格两阶段锁定协议
严格两阶段锁定协议类似于两阶段锁定协议。唯一的区别在于,在严格 2PL 协议中,协议获取的所有排他锁都需要保持,直到协议提交或中止。严格两阶段锁定协议的一个示例是
T1 | T2 |
---|---|
S(A) | |
R(A) | |
S(A) | |
R(A) | |
X(B) | |
R(B) | |
W(B) | |
X(C) | |
R(C) | |
W(C) | |
Unlock(A) | |
Unlock(A) | |
Commit | |
Unlock(B) | |
Commit | |
Unlock(C) |
在上面的示例中,T1 和 T2 使用共享锁共享变量 A,因为仅对 A 执行读取操作。T1 获取对 B 的排他锁以进行写入操作,T2 对 C 执行相同的操作。排他锁仅在事务提交后才释放。但是,共享锁没有此类限制。
严格两阶段锁定协议
严格两阶段锁定协议仅仅是两阶段锁定协议和严格两阶段锁定协议的扩展。在这里,事务持有的所有锁,无论是共享锁还是排他锁,都只在事务提交或中止后才释放。严格两阶段锁定协议的一个示例是
T1 | T2 |
---|---|
S(A) | |
R(A) | |
S(A) | |
R(A) | |
X(B) | |
R(B) | |
W(B) | |
X(C) | |
R(C) | |
W(C) | |
Commit | |
Unlock(A) | |
Unlock(B) | |
Commit | |
Unlock(A) | |
Unlock(C) |
在上面的示例中,T1 和 T2 使用共享锁共享变量 A,因为仅对 A 执行读取操作。T1 获取对 B 的排他锁以进行写入操作,T2 对 C 执行相同的操作。共享锁和排他锁都只在事务提交后才释放。