Part17-Two-Phase Locking
Lock Types
S-LOCK 共享锁 for reads
X-LOCK 排他锁 for writes
上述T1最后R(A) 会导致不可重复读
2PL
允许数据库系统始终以保证Conflict Serializable schedule情况下分发lock
Phase #1 Growing
- 每个txn请求locks 从lock manager
- lock manager grants 或者 denies lock request
Phase #2 Shrinking
- txn只允许进行释放锁,释放先前获得锁,该阶段不可以获得新锁或者升级锁
Cascading abort
级联中止,T2 read T1写入的值,T1回滚,T2也得跟着回滚。
有一些潜在可以串行化的调度不被2PL允许,有些保守了
可能遇到脏读:Strong Strict 2PL 强严格两阶段锁 SS2PL
可能导致死锁:Detection or Prevention
SS2PL
执行完该事务,提交该事务的时候才回去释放锁。
strict 一般是☞ 提交事务的时候事务所做的修改才会被该系统中其他执行的事务所看到。这样的好处有:不会引起级联中止;中止的事务只需要重新恢复修改的tuples原来的值就行。
DeadLock Detection + Prevetion
对于Detection,DBMS创建一个waits-for 图来跟踪每个事务等待获取的锁,每个节点是一个事务,Ti→Tj说明Ti等待Tj释放一个锁。如果出现死锁,只需要选择一个victim,然后kill him,rollback即可。可能只需要回滚部分查询来释放锁,解除死锁。
DeadLock Handling: Victim Selection
- by age 选择时间戳最小的事务
- by progress,执行了最多或者最少查询
- by the # of items already locked 看锁的数量
- by the # of txns that we have to rollback with it
- 考虑某个事务被重启的次数,防止饿死
DeadLock Handling: Rollback Length
回滚多深? completely 或者minimally
Mysql PG可以设置隔离级别+deadlock timeout。PG可以对每个事务单独设置隔离级别。In PG,进入死锁状态之后可以查询catalog显示事务持有那些锁,等待哪些锁,这些锁属于哪个事务进程等信息。
DeadLock Prevention
如果一个事务去拿一个别的事务已经占有的lock,DBMS会kill 这其中一个事务来避免死锁,不需要waits-for graph或者死锁探查的其他算法。
- Wait-Die:Old waits for Young,如果请求txn比holding txn有更高的优先级,那么req txn 等待holding txn 释放锁。反之,直接abort。
- Wound-Wait,young waits for old,如果req txn 优先级大于 holding txn,那么直接抢占式,如果优先级小的话那么请求txn等待。
下面场景:T1 优先级高于 T2,T1 早于T2,第一张图是T2先拿到lock,wait-die T1 wait, wound wait T2 kill and restart。第二张图是T1 grab lock, wait-die T2 die, wound-wait,T2 wait(无法抢占)
wait-die 基本是按照时间戳顺序来发放lock,如果能够保证一种类型的所按照一个方向发放,可能会很好的避免死锁。
当txn重启,是原本的时间戳,因为饿死,新的时间戳可能会导致饿死,但是按照顺序,老的时间戳早晚会被执行。
Hierarchical Locking
层级锁,或者使用不同粒度的lock来,tuple、table、page。
如何是用最少的lock来高效地完成任务?
针对不同的事务使用不同粒度和不同类型的锁
排他锁和共享锁 for leafs of lock tree, intention locks for higher level来提示其他事务你在下面干嘛。Intention Lock允许以共享或排他模式锁定更高级别的节点,而无需检查所有的子节点。如果节点处于Intention 模式,则在树的较低层某个节点上就有该类型的lock。
对应三种lock,Intention-Shared IS,以该节点为根节点的子树下方某处会有一个sharedlock;Intention-Exclusive IX;Shared+Intention-Exclusive SIX,这个节点下面都有S锁,并某个地方有排他锁,是用于读取整个表并且可能会对某个地方进行更新的场景。
-
Locking Protocol
如果想在某个节点有IS\S,至少父节点有IS
要有X IX SIX 父节点要有IX
分层锁在实践中很有用,因为每个txn只需要几个锁。
意图锁有助于提高并发性:
→意图共享(IS):意图以更细的粒度获得S锁。
→Intention-Exclusive (IX):意图以更细的粒度获得X锁。
→共享+意图排他(SIX):同时想要S和IX。
Lock Escalation
锁升级,当获得太多低级锁时,锁升级会动态地请求粗粒度锁。这减少了锁管理器必须处理的请求数量
Lock in Practice
显示设置锁不是SQL的一部分,但是可以hint暗示要用哪种锁。
还有就是为了更新的查询的暗示,我后面会写所以你先帮我拿个排他锁。
Isolation Levels
隔离级别指的是一个事务修改过的对象的值对其他并发事务的可见程度。
可以在十五开始之前就提前设置事务的隔离级别
SET TRANSCATIONISOLATION LEVEL <isolation-level>;
ReadUncommitted读未提交
未提交的事务所做的修改对其他事务可见。
脏读:可能有;不可重复读:可能有;幻读:可能有。
ReadCommited读已提交
只有已提交的事务所做的修改才对其他事务可见。
脏读:无;不可重复读:可能有;幻读:可能有。
RepeatableRead可重复读
如果一个事务不修改对象X的值,则该事务在任何时候读到的X值都等于事务启动时读到的X值。
脏读:无;不可重复读:无;幻读:可能有。
Serializable可串行化
脏读:无;不可重复读:无;幻读:无。