lec 18 transactions with two-phase lock
agenda
Lock types, Two-phase Locking, Deadlock-detection+prevention, Hierarchical Locking
Intention lock
lock type
S-LOCK: shared locks for reads
X-LOCK: exclusive locks for writes
concurrency control ptotocol: Two-phase locking
适合不事先知道全局信息的场景
第一阶段:Phase #1: Growing(增长阶段)
Each txn requests the locks that it needs from the DBMS's lock manager.
每个事务(txn)向数据库管理系统的锁管理器请求它所需要的锁。The lock manager grants/denies lock requests.
锁管理器批准(允许)或拒绝锁请求。
- 深度解析 :在这个阶段,事务只能获取锁 (无论是共享锁 S 还是排他锁 X)或者升级锁 (如将共享锁升级为排他锁)。在这个阶段中,事务绝对不能释放任何锁。随着事务的运行,它持有的锁数量逐渐增加,就像一个"增长"的曲线。
第二阶段:Phase #2: Shrinking(收缩阶段)
The txn is allowed to only release/downgrade locks that it previously acquired. It cannot acquire new locks.
事务只被允许释放或降级它之前已经获得的锁。它不能获取任何新锁。
- 深度解析 :一旦事务释放了它的第一把锁 ,或者将某把锁降级(如排他锁降级为共享锁),事务就立即进入了"收缩阶段"。在这个阶段,锁的数量只能减少,严格禁止再次申请任何新锁。
关键机制总结
- 单向不可逆 :事务的生命周期就像爬山,只能先上山(增长阶段:不断加锁),到达顶点后开始下山(收缩阶段:不断解锁)。一旦开始下山,绝不能再回头上山(不能再加锁)。
- 核心目的:防止事务在释放锁后,又去修改其他相关数据,从而引发"脏读"或"不可重复读"等并发冲突。
2PL可能导致dirty read(级联中断)和死锁
问题: cascading aborting(级联中断)
T1回滚但是T2用到了T1的东西,导致T2必须跟着回滚(T1提前释放锁,T2再次申请)
解决: 强严格的2PL(strong strict )
事务只允许在结束后释放所有锁(提交或终止)
一般严格2PL:排他锁可以在收缩阶段释放,但必须保留共享锁(无法阻止级联中断问题)
严格的定义
A schedule is strict if a value written by a txn is not read or overwritten by other txns until that txn finishes.
如果一个事务(txn)写入的值在它结束之前,既不能被其他事务读取,也不能被其他事务覆盖,那么这个调度就是"严格的"。
2PL Deadlocks
两种办法解决: 死锁检测与死锁预防
dl detection
核心工具:等待图 (Waits-For Graph)
这是数据库在内存中维护的一张动态有向图。图里的每一个点都是一个正在运行的事务。如果事务 1 想要修改数据 A,但数据 A 现在被事务 2 用排他锁锁住了,事务 1 必须排队等候
DBMS周期性检查是否存在循环依赖(环)
在"快速打破死锁"与"消耗资源去寻找死锁"之间存在一种权衡。
dl Handling
需要找一个'victim'事务终止并回滚
选择时需要考虑很多因素(时间戳 进展 持有锁的数量 需要回滚多少其他事务)
rollback length
策略 1:完全回滚(Completely)
策略 2:部分回滚(Partial / Savepoints)
需要用到savepoint机制
Deadlock Prevention
When a txn tries to acquire a lock that is held by another txn, the DBMS kills one of them to prevent a deadlock.
当一个事务(txn)试图获取一把被另一个事务持有的锁时,DBMS 会杀死(干掉)其中一个事务,以预防死锁的发生。
无需维护等待图,也不需要运行复杂的死锁检测算法
每个事务都会在开始时分配一个时间戳(决定优先级)
策略 1:Wait-Die(等或死)------ 别名:"老等新"
(\rightarrow ) If requesting txn has higher priority than holding txn, then requesting txn waits for holding txn.
如果【申请锁的事务】比【持有锁的事务】优先级更高(即老事务申请新事务的锁),那么申请者可以进行等待。(\rightarrow ) Otherwise requesting txn aborts.
否则(即新事务申请老事务的锁),申请者直接自杀(Abort / 中止)。
策略 2:Wound-Wait(伤害或等)------ 别名:"轻伤或等" / "新等老"
(\rightarrow ) If requesting txn has higher priority than holding txn, then holding txn aborts and releases lock.
如果【申请锁的事务】比【持有锁的事务】优先级更高(即老事务申请新事务的锁),那么持有锁的事务(新事务)会被强行干掉(Abort)并释放锁。(\rightarrow ) Otherwise requesting txn waits.
否则(即新事务申请老事务的锁),申请者进行等待。
Lock Granularities(粒度)
给锁分层级
table 和 tuple级非常常见
Intention Lock
意向锁不是用来锁具体数据的,它是加在高层节点上的 "一盏信号灯" ,用来宣告底层已经有人占用了位置。
1.Intention-Shared (IS) ------ 意向共享锁
事务准备去读表里的某几行数据。在给这几行加"读锁(S锁)"之前,先在整张表上挂一盏"IS"灯。
2.Intention-Exclusive (IX) ------ 意向排他锁
事务准备去修改表里的某几行数据。在给这几行加"写锁(X锁)"之前,先在整张表上挂一盏"IX"灯。
3.Shared + Intention-Exclusive (SIX) ------ 共享意向排他锁
- 这是一个复合锁。它同时做两件事:
-
锁住全表(S 锁) :我现在要读取整张表 的所有数据。
-
意向修改(IX 锁) :稍后我还要去修改其中的某几行(去底层加 X 锁)。
locking protocol
这套协议的根本原则是:自上而下,先探路再加锁 。事务不能跳过高层级节点直接去锁底层节点。
1.总则:从最高层级开始
2.读锁(S/IS)的加锁前提
To get S or IS lock on a node, the txn must hold at least IS on parent node. 要在某个节点上获取共享锁(S)或意向共享锁(IS),事务必须在其父节点上至少持有意向共享锁(IS)。
3.写锁(X/IX/SIX)的加锁前提
To get X, IX, or SIX on a node, must hold at least IX on parent node.
要在某个节点上获取排他锁(X)、意向排他锁(IX)或共享意向排他锁(SIX),必须在其父节点上至少持有意向排他锁(IX)。
DBMS可以自动更换到更粗粒度的锁,当事务需要太多低层级的锁
sql语句显示说明 FOR UPDATE
另一个是SKIP LOCKED跳过无法获取共享锁的数据行(用于队列查询)
next:
乐观并发控制 mvcc 隔离层级
远程终端登录命令[ssh -p 42022 root@connect.bjb2.seetacloud.com] 密码[o6xpR2bGjSHN]. 远程工作区在/root/autodl-tmp/dataset