在网上看了很多三级封锁协议的例子,大部分都是不正确的(例如T1加了X锁后,T2还加S锁)。以下是正确的实例。
首先描述一下三级封锁协议。
一级封锁:要写数据,写前加X锁,事务结束才释放。
二级封锁:在一级封锁的基础上,要读数据,读前加S锁,读后释放。
三级封锁:在一级封锁的基础上,要读数据,读前加S锁,事务结束才释放。
一级封锁可以解决丢失修改问题,二级封锁可以再解决读脏数据问题,三级封锁可以再解决不可重复读问题。
一级封锁协议作用实例
不加封锁的情况:
T1 | A的值 | T2 |
Read(A) | 100 | |
100 | Read(A) | |
A=A-10 | ||
Write(A) | 90 | |
A=A-20 | ||
80 | Write(A) |
在上述实例中,T1对A减10,T2对A减20,如果串行执行,A应该减了30,也就是最后结果是70。但上述实例的运行结果是80,出现了丢失修改的问题。
由于T1和T2都需要对A进行写,所以按照一级封锁协议,实际运行应该是:
T1 | A的值 | T2 |
XLock(A) | ||
Read(A) | 100 | |
A-A-10 | 由于加了X锁,无法再加X锁,只能等待 | |
Write(A) | 90 | 等待 |
Unlock(A) | 等待 | |
XLock(A) | ||
90 | Read(A) | |
A=A-20 | ||
70 | Write(A) | |
Unlock(A) |
上述实例运行之后,结果就是正确的,解决了丢失修改的问题。
二级封锁协议作用示例
只遵循一级封锁协议的情况:
T1 | A的值 | T2 |
XLock(A) | ||
Read(A) | 100 | |
A=A-10 | ||
Write(A) | 90 | |
90 | Read(A) | |
Rollback | 100 | |
Unlock(A) |
在上述实例子,T1执行结束后,A的值是100,而T2读到的值是90。这产生了读脏数据的问题。
按照二级封锁协议,T2在读数据前,必须加上S锁,结果如下:
T1 | A的值 | T2 |
XLock(A) | ||
Read(A) | 100 | |
A=A-10 | ||
Write(A) | 90 | |
Rollback | 100 | 由于加了X锁,无法再加S锁,只能等待 |
Unlock(A) | 等待 | |
SLock(A) | ||
100 | Read(A) | |
Unlock(A) |
可以看到,二级封锁协议解决了读脏数据的问题。
三级封锁协议作用示例
遵循二级封锁协议的情况:
T1 | A的值 | T2 |
SLock(A) | ||
Read(A) | 100 | |
Unlock(A) | ||
XLock(A) | ||
100 | Read(A) | |
A=A-10 | ||
90 | Write(A) | |
Unlock(A) | ||
SLock(A) | ||
Read(A) | 90 | |
Unlock(A) |
在上述例子中,T1第一次读A是100,第一次读是90,出现了不可重复读的问题。
按照三级封锁协议,T1在事务结束前才能释放S锁,结果如下:
T1 | A的值 | T2 |
SLock(A) | ||
Read(A) | 100 | |
Read(A) | 100 | 由于加了S锁,不能再加X锁,只能等待 |
Unlock(A) | 等待 | |
XLock(A) | ||
100 | Read(A) | |
A=A-10 | ||
90 | Write(A) | |
Unlock(A) |
可以看到,三级封锁协议解决了不可重复读的问题。