行鎖類型
gap類型
每個行鎖由鎖類型和gap類型組成
例如:
lock_x|lock_ordinary 表示對記錄和記錄之前的間隙加排他鎖
lock_s|lock_gap 表示隻對記錄前的間隙加共享鎖
鎖的相容性:
值得注意的是,持有gap的鎖(lock_gap和lock_ordinary)與其他非lock_insert_intention的鎖都是相容的,也就是說,gap鎖就是為了防止插入的。
這裡的鎖分裂和合并,隻是針對innodb行鎖而言的,而且一般隻作用于gap類型的鎖。
鎖分裂
插入的記錄的間隙存在gap鎖,此時此gap需分裂為兩個gap
鎖繼承
删除的記錄前存在gap鎖,此gap鎖會繼承到要删除記錄的下一條記錄上
鎖遷移
b數結構變化,鎖資訊也會随之遷移. 鎖遷移過程中也涉及鎖繼承。
鎖分裂例子
這裡如果插入(3,3)沒有給(3,3)加lock_x|lock_gap,那麼其他連接配接插入(2,2)就可以成功
隔離級别repeatable-read
驗證:session 1執行insert into t1 values(1,1)發生了鎖等待,說明(2,2)上有gap鎖
隔離級别read-committed
驗證
session 1執行insert into t1 values(1)發生了鎖等待,說明(2)上有gap鎖
而實際在讀送出隔離級别上,insert into t1 values(1)應該可以插入成功,不需要等待的,這個鎖是否繼承值得商榷。
來看一個插入成功的例子
隔離級别serializable
驗證方法同read-committed。
b樹節點發生分裂,合并,删除都會引發鎖的變化。鎖遷移的原則是,b數結構變化前後,鎖住的範圍保證不變。
我們通過例子來說明
節點分裂
假設原節點a(infimum,1,3,supremum) 向右分裂為b(infimum,1,supremum), c(infimum,3,supremum)兩個節點
infimum為節點中虛拟的最小記錄,supremum為節點中虛拟的最大記錄
假設原節點a上鎖為3上lock_s|lock_oridnary,supremum為lock_s|lock_gap,實際鎖住了(1~)
鎖遷移過程大緻為:
1)将3上的gap鎖遷移到c節點3上
2)将a上supremum遷移繼承到c的supremum上
3)将c上最小記錄3的鎖遷移繼承到b的supremum上
遷移完成後鎖的情況如下(lock_update_split_right)
b節點:suprmum lock_s|lock_gap
c節點:3 lock_s|lock_orinary, suprmum lock_s|gap
遷移後仍然鎖住了範圍(1~)
節點向左分裂情形類似
節點合并
以上述節點分裂的逆操作來講述合并過程
b(infimum,1,supremum), c(infimum,3,supremum)兩個節點,向左合并為a節點(infimum,1,3,supremum)
其中b,c節點鎖情況如下
遷移流程如下(lock_update_merge_left):
1)将c節點鎖記錄3遷移到b節點
2)将b節點supremum遷移繼承到a的supremum上
節點向右合并情形類似
節點删除
如果删除節點存在左節點,則将删除節點符合條件的鎖,遷移繼承到左節點supremum上
否則将删除節點符合條件的鎖,遷移繼承到右節點最小使用者記錄上
參考lock_update_discard
bug#73170 二級唯一索引失效。這個bug觸發條件是删除的記錄沒有被purge, 鎖還沒有被繼承的。如果鎖繼承了就不會出現問題。
bug#76927 同樣是二級唯一索引失效。這個bug是鎖繼承機制出了問題。