詳解 MySql InnoDB 中意向鎖的做用

前言

InnoDB 支持多粒度鎖(multiple granularity locking),它容許行級鎖表級鎖共存,而意向鎖就是其中的一種表鎖sql

意向鎖(Intention Locks)

須要強調一下,意向鎖是一種不與行級鎖衝突表級鎖,這一點很是重要。意向鎖分爲兩種:併發

  • 意向共享鎖(intention shared lock, IS):事務有意向對錶中的某些行加共享鎖(S鎖)
    -- 事務要獲取某些行的 S 鎖,必須先得到表的 IS 鎖。
    SELECT column FROM table ... LOCK IN SHARE MODE;
    複製代碼
  • 意向排他鎖(intention exclusive lock, IX):事務有意向對錶中的某些行加排他鎖(X鎖)
    -- 事務要獲取某些行的 X 鎖,必須先得到表的 IX 鎖。
    SELECT column FROM table ... FOR UPDATE;
    複製代碼

即:意向鎖是有數據引擎本身維護的,用戶沒法手動操做意向鎖,在爲數據行加共享 / 排他鎖以前,InooDB 會先獲取該數據行所在在數據表的對應意向鎖。post

意向鎖要解決的問題

咱們先來看一下百度百科上對意向鎖存在乎義的描述:spa

若是另外一個任務試圖在該表級別上應用共享或排它鎖,則受到由第一個任務控制的表級別意向鎖的阻塞。第二個任務在鎖定該表前沒必要檢查各個頁或行鎖,而只需檢查表上的意向鎖。code

設想這樣一張 users 表: MySqlInnoDBRepeatable-Read:users(id PK,name)事務

id name
1 ROADHOG
2 Reinhardt
3 Tracer
4 Genji
5 Hanzo
6 Mccree

事務 A 獲取了某一行的排他鎖,並未提交:ip

SELECT * FROM users WHERE id = 6 FOR UPDATE;
複製代碼

事務 B 想要獲取 users 表的表鎖:get

LOCK TABLES users READ;
複製代碼

由於共享鎖與排他鎖互斥,因此事務 B 在視圖對 users 表加共享鎖的時候,必須保證:it

  • 當前沒有其餘事務持有 users 表的排他鎖。
  • 當前沒有其餘事務持有 users 表中任意一行的排他鎖 。

爲了檢測是否知足第二個條件,事務 B 必須在確保 users表不存在任何排他鎖的前提下,去檢測表中的每一行是否存在排他鎖。很明顯這是一個效率不好的作法,可是有了意向鎖以後,狀況就不同了:io

意向鎖的兼容互斥性

意向鎖是怎麼解決這個問題的呢?首先,咱們須要知道意向鎖之間的兼容互斥性:

意向共享鎖(IS) 意向排他鎖(IX)
意向共享鎖(IS) 兼容 兼容
意向排他鎖(IX) 兼容 兼容

意向鎖之間是互相兼容的,emmm......那你存在的意義是啥?

雖然意向鎖和自家兄弟互相兼容,可是它會與普通的排他 / 共享鎖互斥:

意向共享鎖(IS) 意向排他鎖(IX)
共享鎖(S) 兼容 互斥
排他鎖(X) 互斥 互斥

注意:這裏的排他 / 共享鎖指的都是表鎖!!!意向鎖不會與行級的共享 / 排他鎖互斥!!!

如今咱們回到剛纔 users 表的例子:

事務 A 獲取了某一行的排他鎖,並未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;
複製代碼

此時 users 表存在兩把鎖:users 表上的意向排他鎖與 id 爲 6 的數據行上的排他鎖

事務 B 想要獲取 users 表的共享鎖:

LOCK TABLES users READ;
複製代碼

此時事務 B 檢測事務 A 持有 users 表的意向排他鎖,就能夠得知事務 A 必然持有該表中某些數據行的排他鎖,那麼事務 Busers 表的加鎖請求就會被排斥(阻塞),而無需去檢測表中的每一行數據是否存在排他鎖。

意向鎖的併發性

這就牽扯到我前面屢次強調的一件事情:

意向鎖不會與行級的共享 / 排他鎖互斥!!!
意向鎖不會與行級的共享 / 排他鎖互斥!!!
意向鎖不會與行級的共享 / 排他鎖互斥!!!

重要的話要加粗說三遍,正由於如此,意向鎖並不會影響到多個事務對不一樣數據行加排他鎖時的併發性(否則咱們直接用普通的表鎖就好了)。

最後咱們擴展一下上面 users 表的例子來歸納一下意向鎖的做用(一條數據從被鎖定到被釋放的過程當中,可能存在多種不一樣鎖,可是這裏咱們只着重表現意向鎖):

id name
1 ROADHOG
2 Reinhardt
3 Tracer
4 Genji
5 Hanzo
6 Mccree

事務 A 先獲取了某一行的排他鎖,並未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;
複製代碼
  1. 事務 A 獲取了 users 表上的意向排他鎖
  2. 事務 A 獲取了 id 爲 6 的數據行上的排他鎖

以後事務 B 想要獲取 users 表的共享鎖

LOCK TABLES users READ;
複製代碼
  1. 事務 B 檢測到事務 A 持有 users 表的意向排他鎖
  2. 事務 Busers 表的加鎖請求被阻塞(排斥)。

最後事務 C 也想獲取 users 表中某一行的排他鎖

SELECT * FROM users WHERE id = 5 FOR UPDATE;
複製代碼
  1. 事務 C 申請 users 表的意向排他鎖
  2. 事務 C 檢測到事務 A 持有 users 表的意向排他鎖
  3. 由於意向鎖之間並不互斥,因此事務 C 獲取到了 users 表的意向排他鎖
  4. 由於id 爲 5 的數據行上不存在任何排他鎖,最終事務 C 成功獲取到了該數據行上的排他鎖

總結

  1. InnoDB 支持多粒度鎖,特定場景下,行級鎖能夠與表級鎖共存。
  2. 意向鎖之間互不排斥,但除了 IS 與 S 兼容外,意向鎖會與 共享鎖 / 排他鎖 互斥
  3. IX,IS是表級鎖,不會和行級的X,S鎖發生衝突。只會和表級的X,S發生衝突。
  4. 意向鎖在保證併發性的前提下,實現了行鎖和表鎖共存知足事務隔離性的要求。

參考資料:

擴展閱讀:

相關文章
相關標籤/搜索