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

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

InnoDB存儲引擎中的鎖

 InnoDB存儲引擎實現了以下兩種標準的行級鎖:sql

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

  若是一個事務T1已經獲取了行r的共享鎖,那麼另一個事務T2能夠馬上得到行r的共享鎖,由於讀取並不會改變數據,能夠進行併發的讀取操做;但若其餘的事務T3想要獲取行r的排他鎖,則必須等待事務T1和T2釋放行r上的共享鎖以後才能繼續,由於獲取排他鎖通常是爲了改變數據,因此不能同時進行讀取或則其餘寫入操做。數據庫

X S
X 不兼容 不兼容
S 不兼容 兼容

 InnoDB存儲引擎支持多粒度鎖定,這種鎖定容許事務在行級上的鎖和表級上的鎖同時存在。爲了支持在不一樣粒度上進行加鎖操做,InnoDB存儲引擎支持一種稱爲意向鎖的鎖方式。意向鎖是將鎖定的對象分爲多個層次,意向鎖意味着事務但願在更細粒度上進行加鎖。bash

 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鎖。若是其中任何一個部分致使等待,那麼該操做須要等待粗粒度鎖的完成。spa

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的一致性非鎖定讀相關的知識,請你們持續關注。

相關文章
相關標籤/搜索