MySQL探祕(五):InnoDB鎖的型別和狀態查詢

程式設計師歷小冰發表於2018-11-04

 鎖是資料庫系統區分於檔案系統的一個關鍵特性。資料庫使用鎖來支援對共享資源進行併發訪問,提供資料的完整性和一致性。此外,資料庫事務的隔離性也是通過鎖實現的。InnoDB在此方面一直優於其他資料庫引擎。InnoDB會在行級別上對錶資料上鎖,而MyISAM只能在表級別上鎖,二者效能差異可想而知。

InnoDB儲存引擎中的鎖

 InnoDB儲存引擎實現瞭如下兩種標準的行級鎖:

  • 共享鎖(S Lock),允許事務讀取一行
  • 排他鎖(X Lock),允許事務刪除或更新一行資料

  如果一個事務T1已經獲取了行r的共享鎖,那麼另外一個事務T2可以立刻獲得行r的共享鎖,因為讀取並不會改變資料,可以進行併發的讀取操作;但若其他的事務T3想要獲取行r的排他鎖,則必須等待事務T1和T2釋放行r上的共享鎖之後才能繼續,因為獲取排他鎖一般是為了改變資料,所以不能同時進行讀取或則其他寫入操作。

X S
X 不相容 不相容
S 不相容 相容

 InnoDB儲存引擎支援多粒度鎖定,這種鎖定允許事務在行級上的鎖和表級上的鎖同時存在。為了支援在不同粒度上進行加鎖操作,InnoDB儲存引擎支援一種稱為意向鎖的鎖方式。意向鎖是將鎖定的物件分為多個層次,意向鎖意味著事務希望在更細粒度上進行加鎖。

 InnoDB儲存引擎的意向鎖即為表級別的鎖。設計目的主要是為了在一個事務中揭示下一行將被請求的鎖型別。其支援兩種意向鎖:

  • 意向共享鎖(IS Lock),事務想要獲得一張表中某幾行的共享鎖
  • 意向排他鎖(IX Lock),事務想要獲得一張表中某幾行的排他鎖

 需要注意的是意向鎖是表級別的鎖,它不會和行級的X,S鎖發生衝突。只會和表級的X,S發生衝突。故表級別的意向鎖和表級別的鎖的相容性如下表所示。

IS IX S X
IS 相容 相容 相容 不相容
IX 相容 相容 不相容 不相容
S 相容 不相容 相容 不相容
X 不相容 不相容 不相容 不相容

 向一個表新增表級X鎖的時候(執行ALTER TABLE, DROP TABLE, LOCK TABLES等操作),如果沒有意向鎖的話,則需要遍歷所有整個表判斷是否有行鎖的存在,以免發生衝突。如果有了意向鎖,只需要判斷該意向鎖與即將新增的表級鎖是否相容即可。因為意向鎖的存在代表了,有行級鎖的存在或者即將有行級鎖的存在,因而無需遍歷整個表,即可獲取結果。

層次結構.jpg

 如果將上鎖的物件看成一棵樹,那麼對最下層的物件上鎖,也就是對最細粒度的物件進行上鎖,那麼首先需要對粗粒度的物件上鎖。如上圖所示,如果需要對錶1的記錄m行上X鎖,那麼需要先對錶1加意向IX鎖,然後對記錄m上X鎖。如果其中任何一個部分導致等待,那麼該操作需要等待粗粒度鎖的完成。

InnoDB鎖相關狀態查詢

 使用者可以使用INFOMATION_SCHEMA庫下的INNODB_TRX、INNODB_LOCKS和INNODB_LOCK_WAITS表來監控當前事務並分析可能出現的鎖問題。INNODB_TRX的定義如下表所示,其由8個欄位組成。

欄位名 說明
trx_id InnoDB儲存引擎內部唯一的事務ID
trx_state 當前事務的狀態
trx_started 事務的開始時間
trx_request_lock_id 等待事務的鎖ID。如果trx_state的狀態為LOCK WAIT,那麼該欄位代表當前事務等待之前事務佔用的鎖資源ID
trx_wait_started 事務等待的時間
trx_weight 事務的權重,反映了一個事務修改和鎖住的行數,當發生死鎖需要回滾時,會選擇該數值最小的進行回滾
trx_mysql_thread_id 執行緒ID,SHOW PROCESSLIST 顯示的結果
trx_query 事務執行的SQL語句
mysql> SELECT * FROM information_schema.INNODB_TRX\G;
************************************* 1.row *********************************************
trx_id:  7311F4
trx_state: LOCK WAIT
trx_started: 2010-01-04 10:49:33
trx_requested_lock_id: 7311F4:96:3:2
trx_wait_started: 2010-01-04 10:49:33
trx_weight: 2
trx_mysql_thread_id: 471719
trx_query: select * from parent lock in share mode
複製程式碼

 INNODB_TRX表只能顯示當前執行的InnoDB事務,並不能直接判斷鎖的一些情況。如果需要檢視鎖,則還需要訪問表INNODB_LOCKS,該表的欄位組成如下表所示。

欄位名 說明
lock_id 鎖的ID
lock_trx_id 事務的ID
lock_mode 鎖的模式
lock_type 鎖的型別,表鎖還是行鎖
lock_table 要加鎖的表
lock_index 鎖住的索引
lock_space 鎖住的space id
lock_page 事務鎖定頁的數量,若是表鎖,則該值為NULL
lock_rec 事務鎖定行的數量,如果是表鎖,則該值為NULL
lock_data 事務鎖住記錄的主鍵值,如果是表鎖,則該值為NULL
mysql> SELECT * FROM information_schema.INNODB_LOCKS\G;
*************************************** 1.row *************************************
lock_id: 7311F4:96:3:2
lock_trx_id: 7311F4
lock_mode: S
lock_type: RECORD
lock_table: 'mytest'.'parent'
lock_index: 'PRIMARY'
lock_space: 96
lock_page: 3
lock_rec: 2
lock_data: 1
複製程式碼

 通過表INNODB_LOCKS檢視每張表上鎖的情況後,使用者就可以來判斷由此引發的等待情況。當時當事務量非常大,其中鎖和等待也時常發生,這個時候就不那麼容易判斷。但是通過表INNODB_LOCK_WAITS,可以很直觀的反應當前事務的等待。表INNODB_LOCK_WAITS由四個欄位組成,如下表所示。

欄位名 說明
requesting_trx_id 申請鎖資源的事務ID
requesting_lock_id 申請的鎖的ID
blocking_trx_id 阻塞的事務ID
blocking_lock_id 阻塞的鎖的ID
mysql> SELECT * FROM information_schema.INNODB_LOCK_WAITS\G;
*******************************************1.row************************************
requesting_trx_id: 7311F4
requesting_lock_id: 7311F4:96:3:2
blocking_trx_id: 730FEE
blocking_lock_id: 730FEE:96:3:2
複製程式碼

 通過上述的SQL語句,使用者可以清楚直觀地看到哪個事務阻塞了另一個事務,然後使用上述的事務ID和鎖ID,去INNODB_TRX和INNDOB_LOCKS表中檢視更加詳細的資訊。

後記

 我們後續還會學習InnoDB的一致性非鎖定讀相關的知識,請大家持續關注。

MySQL探祕(五):InnoDB鎖的型別和狀態查詢

相關文章