鎖的分類
- Innodb的鎖分爲兩種:1、輕量級的閂鎖(latch),保護內存中的數據結構;2、鎖(lock),保護數據,一般僅在commit或rollback後釋放。
- lock的分類,SS兼容,其餘互斥:
- 共享鎖(S Lock),允許事務讀一行記錄。
- 排它鎖(X Lock),允許事務刪除或更新一條記錄。
- 意向鎖:表級鎖,事務希望在更細粒度上加鎖。由於Innodb支持的是行級鎖,意向鎖不會阻塞除全表掃描之外的請求。
- 意向共享鎖:事務希望獲得某幾行的共享鎖。
- 意向排它鎖:事務希望獲得某幾行的排它鎖。
讀取加鎖
一致性非鎖定讀
- 如果讀取的行由於update或delete,加X鎖,不會等鎖釋放,而是讀行的快照(undo段實現)。Innodb快照讀。
一致性鎖定讀
- 對select語句顯示加鎖。
- 對讀取的行加X鎖:select … for update。
- 對讀取的行加S鎖:select … lock in share mode。
自增長和鎖
- 之前使用自增長計數器,是一種特殊的表鎖,完成自增長值插入的sql後生效。
- 5.1.22之後使用輕量級的互斥量自增長機制。
- sequence id不使用數據庫自增長,提高插入效率。
外鍵和鎖
- 外鍵列,如果沒有顯式的加索引,innodb會自動加索引,避免表鎖。
- 外鍵值插入時:需要查詢父表的記錄,用一致性鎖定讀,加S鎖。
- 儘量在業務層保證數據的一致性,減小數據的壓力。
加鎖算法
Record Lock
Gap Lock
Next-Key Lock
- 鎖範圍,包括記錄本身。以上兩個鎖的和。
- innodb查詢的列是輔助索引上的鍵值,則會對鍵值加Next-key lock,並且對下一個鍵值加Gap Lock。
- RR級別使用,可解決幻讀問題。
加鎖規則
- 加鎖規則可以概括爲:兩個原則、兩個優化和一個bug:
- 原則1:加鎖的基本單位是索引區間,前開後閉。
- 原則2:查找過程中訪問到的對象纔會加鎖。
- 優化1:索引上的等值查詢,給唯一索引加鎖的時,next-key lock退化成行鎖。
- 優化2:索引上的等值查詢,給非唯一索引加鎖時,向右遍歷時且鎖區間最後一個值不滿足等值條件的時候,next-key lock退化爲間隙鎖。
- 1個bug:唯一索引上的範圍查詢會訪問到不滿足條件的第一個值爲止。
- 參考。
例子
Table t (
a int,
b int,
primary key(a),
key(b)
)
- 如果查詢條件無索引,執行
select * from t where b = 3 for update
,走聚集索引全表掃描,所有記錄加鎖。
- 表中有兩條索引,(1,1),(3,1),(5,3),(7,6)這幾條記錄。
- b列輔助索引,加next-key lock,索引分爲幾段加鎖區間:(-∞,1],(1,3],(3,6],(6,+∞)。
- 執行
select * from t where b = 3 for update
,會對兩條索引分別加鎖。
- 輔助索引:加Next-key Lock,並對下一個鍵值加gap lock,鎖定輔助索引b的範圍(1,3]和(3,6)。
- 聚集索引:由於查詢未使用覆蓋索引,對a=5聚集索引加Record Lock。
- 執行
select * from t where b > 2 for update
。
- 輔助索引:鎖住b[2,+∞)。
- 聚集索引:由於查詢未使用覆蓋索引,加鎖的輔助索引值對應的聚集索引都加鎖。
- 詳細的加鎖樣例。
解鎖算法
- 事務提交時釋放鎖。
- 事務1 加X鎖,未提交之前事務2 在改鎖上寫操作阻塞。