解释一下死锁和活锁的定义,以及说明一下如何预防
活锁类似于OS中的饥饿,比如某些事务长时间无法对其想要使用的数据进行加锁的情况。一般通过先来先服务的算法即可解决。
死锁指有时候不同的事务需要对多个数据进行加锁才能继续执行,但是它们都互相持有对方需要的锁,导致多个事务僵持,无法继续运行的现象叫死锁。一般通过超时检测法、一次性分配法、顺序封锁法
什么叫可串行性
事务的并发执行可能会出现错误的结果,若我们只顺序执行不同的事务,则一定会得到正确的结果。
那么我们可以以顺序执行的结果作为评判标准,来评价多个事务并行执行后的结果的对错。如果一个并行执行的事务最后可以和某一个串行执行得到相同的结果,那么我们就认为这个并行执行是正确的,并称其为可串行化的。
可串行化的充分条件
充分条件1:若对于并发事务,通过调整其可以交换(不可以交换的是同一事务的任意两个操作或者不同事务的冲突操作)的步骤,使其变成串行化的调度,我们就称这个调度是冲突可串行化的调度,然后冲突可串行化的调度一定是可串行话的。
充分条件2:遵守两段锁协议的,一定是可串行化的
如何产生可串行化的调度?
两段锁协议:第一阶段只能上锁,一旦释放任意一个锁,则表示进入第二阶段,此时不能再加任何锁,只能放锁。如果一个事务可以划分为这两段,则一定是可串行化的
PS:第一阶段又叫扩展阶段,第二阶段又叫收缩阶段
PS:两段锁和一次封锁法的区别和联系。一次封锁法要求事务在运行时一次性申请完所有的资源,否则不申请,此外,显然它也会在用完后一起释放锁,所以一次封锁法一定是遵守2PL的。但是两段锁只是保证可串行化的协议,即它只保证并行事务之间不会发生不一致性,但是并不保证不会死锁。注意区别。
粒度
指封锁对象的大小。属性?属性集?元组?关系?甚至是页和物理块。
锁的粒度直接影响事务的并发程度进而影响DBMS的性能。
所以我们对于事务不同的需要应该选择不同粒度的锁,这就叫多粒度封锁。
多粒度锁及其机制
这里以三粒度锁为例。
对一个节点加锁意味着对其后面所属的节点也会加锁。本身被加锁,这叫显式封锁;由于上级被上锁导致自己也被加锁,这叫隐式封锁。
假如现在想对R1加锁,则首先要检查其自身是否有冲突,其次检查上层所有节点是否冲突(比如现在如果有个锁把整个数据库都锁了,则不可以对R1上锁),再检查下层所有节点是否冲突(比如现在正在对一个元组写,上面肯定是有个X锁的,则不能再对R1上锁)
意向锁
意向锁是一种表明该节点的某下属节点已被上锁的特殊锁。主要是为了解决上面多粒度锁检查开销大的问题。比如上图中,若想对一个元素加锁,则需要顺着往上把所有经过的地方全部加上意向锁。
根据Slock和Xlock,配合意向锁可以形成IS/IX/SIX锁,分别指读意向锁/写意向锁/读写意向锁。
PS:其实复杂主要就是在于这种树形结构找爸爸的步骤很少,但是儿子却可能非常多,所以把儿子的事解决了,检查的工作量就少多了