之前讲的都是概念,关于实际怎么防止调度读到或者写到自己不该写的东西我们其实一!点!都!没!讲!啦啦啦
实际中实现isolation这个性质的机制有两种,一种被称为TWO_PHASE LOCKING 还有一个被称为snapshot isolation,前面那个字面就很好理解,二步锁定,后面那个直接翻译被称为快照隔离。下面我们讲的是锁定。
锁定分为两种:
shared,即分享锁定,这个被分享锁定所锁定的数据可以被其他的调度套上分享锁定。这个锁定的拥有者对于锁定数据的操作权限仅限于读取数据。
exclusive, 即排外锁定,被这种锁锁定的数据不能被其他的任何调度锁定,被锁定的数据可以被持有锁定的调度读和写。
在这里需要介绍一个新的概念叫做concurrency control manager.这个系统负责控制数据库里所有的锁定需求。
锁的兼容定义见上。
我们定义LOCK-S(Q)为用share模式锁定数据Q,LOCK-X(Q)为用excluded模式锁定数据Q,UNLOCK(Q)来取消锁定Q。
下面进行对于锁定的两种使用方式的讨论。
理解上图以后我们发现,display(A+B)显示出的结果不是正确的,因为T1过早的解锁了B数据,而它本身的活动还没有完结 ,而事实上我们也很明白这个结果必然是错的,因为T1的剩下部分中有写的部分,这样的调度并不属于一个serializable的调度。
所以事实上这个情况属于T1过早的解开了锁,导致的数据不连续。
而当我们这么写的时候,就不需要担心不连续了,但是很明显的,这个调度并跑不起来,原因是显而易见的。
而这种相互卡死的情况被称为锁死,当遇到锁死的时候,必然伴随着回滚,而回滚同时也会将原来锁死的数据解锁。
而在设计模式的时候我们就遇到了这个问题,我们到底是要锁死还是要数据不连续——很明显前者好一点,因为可以通过数据回滚来解决,而数据不连续导致的外部输出是很难解决的。
接下来给大家带来一个定义:
很好理解的概念吧(233
对于一个调度,如果它是符合上述封锁协议规定的,那么我们称它为合法调度,我们称一个封锁协议保证可串行性,如果在它之下的所有合法调度都是可串行化的话,这个可以用检查内部的关系图有无环来确定。
接下来介绍饿死的概念:
饿死,很明显,如果说在一个要求lock-x的调度前面跟着若干个要求lock-s的调度,这个lock-x的调度将被无限延期,所以说处理调度的法则为:
1.要求的数据没有被要求不兼容的锁锁住
2.前面没有任何比它要求更早的锁。
简单的说,就是按递交顺序排序。