MySQL鎖機制——你想知道的都在這!

1、鎖的類型

行鎖

  • 共享鎖(S Lock)容許事務讀一行數據
  • 排它鎖 (X Lock) 容許事務寫一行數據

表鎖(意向鎖)

鎖定容許事務在行級上的鎖和表級上的鎖同時存在。爲了支持在不一樣粒度上進行加鎖操做,InnoDB存儲引擎支持一種額外的鎖方式html

  • 意向共享鎖(IS Lock)事務想要得到一張表中某幾行的共享鎖mysql

  • 意向排他鎖(IX Lock)事務想要得到一張表中某幾行的排他鎖算法

因爲InnoDB存儲引擎支持的是行級別的鎖,所以意向鎖其實不會阻塞除全表掃之外的任何請求。故表級意向鎖與行級鎖的兼容性以下所示sql

若將上鎖的對象當作一棵樹,那麼對最下層的對象上鎖,也就是對最細粒度的對象進行上鎖,那麼首先須要對粗粒度的對象上鎖。例上圖,若是須要對頁上的記錄r進行上X鎖,那麼分別須要對數據庫A、表、頁上意向鎖IX,最後對記錄r上X鎖。若其中任何一個部分致使等待,那麼該操做須要等待粗粒度鎖的完成。舉例來講,在對記錄r加X鎖以前,已經有事務對錶1進行了S表鎖,那麼表1上已存在S鎖,以後事務須要對記錄r在表1上加上IX,因爲不兼容,因此該事務須要等待表鎖操做的完成。數據庫

意向鎖到底有什麼做用?

innodb的意向鎖主要用戶多粒度的鎖並存的狀況。好比事務A要在一個表上加S鎖,若是表中的一行已被事務B加了X鎖,那麼該鎖的申請也應被阻塞。若是表中的數據不少,逐行檢查鎖標誌的開銷將很大,系統的性能將會受到影響。爲了解決這個問題,能夠在表級上引入新的鎖類型來表示其所屬行的加鎖狀況,這就引出了「意向鎖」的概念。架構

舉個例子,若是表中記錄1億,事務A把其中有幾條記錄上了行鎖了,這時事務B須要給這個表加表級鎖,若是沒有意向鎖的話,那就要去表中查找這一億條記錄是否上鎖了。若是存在乎向鎖,那麼假如事務A在更新一條記錄以前,先加意向鎖,再加X鎖,事務B先檢查該表上是否存在乎向鎖,存在的意向鎖是否與本身準備加的鎖衝突,若是有衝突,則等待直到事務A釋放,而無須逐條記錄去檢測。事務B更新表時,其實無須知道到底哪一行被鎖了,它只要知道反正有一行被鎖了就好了。併發

主要做用是處理行鎖和表鎖之間的矛盾,可以顯示「某個事務正在某一行上持有了鎖,或者準備去持有鎖」post

2、鎖的算法

  • Record Lock:單個行記錄上的鎖性能

  • Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄自己優化

  • Next-Key Lock∶Gap Lock+Record Lock,鎖定一個範圍、索引之間的間隙,而且鎖定記錄自己;目的是爲了防止幻讀

3、mysql如何作到讀寫並行(多版本控制)?

多版本併發控制 MVCC,是行級鎖的一個變種,經過保存數據在某個時間節點的快照(snapshot),相似實現了行級鎖。由此不一樣事務對同一表,同一時刻看到的數據多是不同的。 實現上經過在不一樣的數據行後增長建立日期版本號和刪除日期版本號,且版本號不斷遞增,進而實現了數據快照

讀的類型

  • 一致性非鎖定讀(快照讀)
    • 在事務隔離級別提交讀(RC)和可重複讀(RR)下,InnoDB存儲引擎使用非鎖定的一致性讀
      • RC模式下,讀取最新的快照
      • RR模式下,讀取事務開始時的快照
  • 一致性鎖定讀 (當前讀)
    • 隔離級別爲未提交讀(RN)時讀取都是當前讀
    • SELECT…FOR UPDATE (加寫鎖)
    • SELECT…LOCK IN SHARE MODE (加讀鎖)

4、加鎖處理分析

下面兩條簡單的SQL,他們加什麼鎖?

select * from t1 where id = 10

delete from t1 where id = 10

若是要分析加鎖狀況,必須還要知道如下的一些前提,前提不一樣,加鎖處理的方式也不一樣

  • 前提一:id列是否是主鍵?
  • 前提二:當前系統的隔離級別是什麼?
  • 前提三:id列若是不是主鍵,那麼id列上有索引嗎?
  • 前提四:id列上若是有二級索引,那麼這個索引是惟一索引嗎?
  • 前提五:兩個SQL的執行計劃是什麼?索引掃描?全表掃描?

根據上述狀況,有如下幾種組合

  • 組合一:id列是主鍵,RC隔離級別
  • 組合二:id列是二級惟一索引,RC隔離級別
  • 組合三:id列是二級非惟一索引,RC隔離級別
  • 組合四:id列上沒有索引,RC隔離級別
  • 組合五:id列是主鍵,RR隔離級別
  • 組合六:id列是二級惟一索引,RR隔離級別
  • 組合七:id列是二級非惟一索引,RR隔離級別
  • 組合八:id列上沒有索引,RR隔離級別
  • 組合九:Serializable隔離級別

排列組合尚未列舉徹底,可是看起來,已經不少了。真的有必要這麼複雜嗎?事實上,要分析加鎖,就是須要這麼複雜。可是從另外一個角度來講,只要你選定了一種組合,SQL須要加哪些鎖,其實也就肯定了。接下來挑幾個比較經典的組合

組合一:id主鍵+RC

  這個組合,是最簡單,最容易分析的組合。id是主鍵,Read Committed隔離級別,給定SQL:delete from t1 where id = 10; 只須要將主鍵上,id = 10的記錄加上X鎖便可。以下圖所示:            

      結論:id是主鍵時,此SQL只須要在id=10這條記錄上加X鎖便可。

組合二:id惟一索引+RC

  這個組合,id不是主鍵,而是一個Unique的二級索引鍵值。那麼在RC隔離級別下,delete from t1 where id = 10; 須要加什麼鎖呢?見下圖:        

  此組合中,id是unique索引,而主鍵是name列。此時,加鎖的狀況因爲組合一有所不一樣。因爲id是unique索引,所以delete語句會選擇走id列的索引進行where條件的過濾,在找到id=10的記錄後,首先會將unique索引上的id=10索引記錄加上X鎖,同時,會根據讀取到的name列,回主鍵索引(聚簇索引),而後將聚簇索引上的name = ‘d’ 對應的主鍵索引項加X鎖。爲何聚簇索引上的記錄也要加鎖?試想一下,若是併發的一個SQL,是經過主鍵索引來更新:update t1 set id = 100 where name = ‘d’; 此時,若是delete語句沒有將主鍵索引上的記錄加鎖,那麼併發的update就會感知不到delete語句的存在,違背了同一記錄上的更新/刪除須要串行執行的約束。

結論:若id列是unique列,其上有unique索引。那麼SQL須要加兩個X鎖,一個對應於id unique索引上的id = 10的記錄,另外一把鎖對應於聚簇索引上的[name='d',id=10]的記錄。

組合三:id非惟一索引+RC

  相對於組合1、二,組合三又發生了變化,隔離級別仍舊是RC不變,可是id列上的約束又下降了,id列再也不惟一,只有一個普通的索引。假設delete from t1 where id = 10; 語句,仍舊選擇id列上的索引進行過濾where條件,那麼此時會持有哪些鎖?一樣見下圖:

  根據此圖,能夠看到,首先,id列索引上,知足id = 10查詢條件的記錄,均已加鎖。同時,這些記錄對應的主鍵索引上的記錄也都加上了鎖。與組合二惟一的區別在於,組合二最多隻有一個知足等值查詢的記錄,而組合三會將全部知足查詢條件的記錄都加鎖。

結論:若id列上有非惟一索引,那麼對應的全部知足SQL查詢條件的記錄,都會被加鎖。同時,這些記錄在主鍵索引上的記錄,也會被加鎖。

組合四:id無索引+RC

  相對於前面三個組合,這是一個比較特殊的狀況。id列上沒有索引,where id = 10;這個過濾條件,無法經過索引進行過濾,那麼只能走全表掃描作過濾。對應於這個組合,SQL會加什麼鎖?或者是換句話說,全表掃描時,會加什麼鎖?這個答案也有不少:有人說會在表上加X鎖;有人說會將聚簇索引上,選擇出來的id = 10;的記錄加上X鎖。那麼實際狀況呢?請看下圖:

  因爲id列上沒有索引,所以只能走聚簇索引,進行所有掃描。從圖中能夠看到,知足刪除條件的記錄有兩條,可是,聚簇索引上全部的記錄,都被加上了X鎖。不管記錄是否知足條件,所有被加上X鎖。既不是加表鎖,也不是在知足條件的記錄上加行鎖。

  有人可能會問?爲何不是隻在知足條件的記錄上加鎖呢?這是因爲MySQL的實現決定的。若是一個條件沒法經過索引快速過濾,那麼存儲引擎層面就會將全部記錄加鎖後返回,而後由MySQL Server層進行過濾。所以也就把全部的記錄,都鎖上了。

注:在實際的實現中,MySQL有一些改進,在MySQL Server過濾條件,發現不知足後,會調用unlock_row方法,把不知足條件的記錄放鎖 (違背了2PL的約束)。這樣作,保證了最後只會持有知足條件記錄上的鎖,可是每條記錄的加鎖操做仍是不能省略的。

結論:若id列上沒有索引,SQL會走聚簇索引的全掃描進行過濾,因爲過濾是由MySQL Server層面進行的。所以每條記錄,不管是否知足條件,都會被加上X鎖。可是,爲了效率考量,MySQL作了優化,對於不知足條件的記錄,會在判斷後放鎖,最終持有的,是知足條件的記錄上的鎖,可是不知足條件的記錄上的加鎖/放鎖動做不會省略。同時,優化也違背了2PL的約束。

組合五:id主鍵+RR

  上面的四個組合,都是在Read Committed隔離級別下的加鎖行爲,接下來的四個組合,是在Repeatable Read隔離級別下的加鎖行爲。

  組合五,id列是主鍵列,Repeatable Read隔離級別,針對delete from t1 where id = 10; 這條SQL,加鎖與組合一:[id主鍵,Read Committed]一致。

組合六:id惟一索引+RR

  與組合五相似,組合六的加鎖,與組合二:[id惟一索引,Read Committed]一致。兩個X鎖,id惟一索引知足條件的記錄上一個,對應的聚簇索引上的記錄一個。

組合七:id非惟一索引+RR

  還記得前面提到的MySQL的四種隔離級別的區別嗎?RC隔離級別容許幻讀,而RR隔離級別,不容許存在幻讀。可是在組合5、組合六中,加鎖行爲又是與RC下的加鎖行爲徹底一致。那麼RR隔離級別下,

  組合七,Repeatable Read隔離級別,id上有一個非惟一索引,執行delete from t1 where id = 10; 假設選擇id列上的索引進行條件過濾,最後的加鎖行爲,是怎麼樣的呢?一樣看下面這幅圖:       

  此圖,相對於組合三:[id列上非惟一鎖,Read Committed]看似相同,其實卻有很大的區別。最大的區別在於,這幅圖中多了一個GAP鎖,並且GAP鎖看起來也不是加在記錄上的,倒像是加載兩條記錄之間的位置,GAP鎖有何用?

  其實這個多出來的GAP鎖,就是RR隔離級別,相對於RC隔離級別,不會出現幻讀的關鍵。確實,GAP鎖鎖住的位置,也不是記錄自己,而是兩條記錄之間的GAP。

  如何保證兩次當前讀返回一致的記錄,那就須要在第一次當前讀與第二次當前讀之間,其餘的事務不會插入新的知足條件的記錄並提交。爲了實現這個功能,GAP鎖應運而生。

  如圖中所示,有哪些位置能夠插入新的知足條件的項 (id = 10),考慮到B+樹索引的有序性,知足條件的項必定是連續存放的。記錄[6,c]以前,不會插入id=10的記錄;[6,c]與[10,b]間能夠插入[10, aa];[10,b]與[10,d]間,能夠插入新的[10,bb],[10,c]等;[10,d]與[11,f]間能夠插入知足條件的[10,e],[10,z]等;而[11,f]以後也不會插入知足條件的記錄。所以,爲了保證[6,c]與[10,b]間,[10,b]與[10,d]間,[10,d]與[11,f]不會插入新的知足條件的記錄,MySQL選擇了用GAP鎖,將這三個GAP給鎖起來。

  Insert操做,如insert [10,aa],首先會定位到[6,c]與[10,b]間,而後在插入前,會檢查這個GAP是否已經被鎖上,若是被鎖上,則Insert不能插入記錄。所以,經過第一遍的當前讀,不只將知足條件的記錄鎖上 (X鎖),與組合三相似。同時仍是增長3把GAP鎖,將可能插入知足條件記錄的3個GAP給鎖上,保證後續的Insert不能插入新的id=10的記錄,也就杜絕了同一事務的第二次當前讀,出現幻象的狀況。

  有心的朋友看到這兒,能夠會問:既然防止幻讀,須要靠GAP鎖的保護,爲何組合5、組合六,也是RR隔離級別,卻不須要加GAP鎖呢?

  首先,這是一個好問題。其次,回答這個問題,也很簡單。GAP鎖的目的,是爲了防止同一事務的兩次當前讀,出現幻讀的狀況。而組合五,id是主鍵;組合六,id是unique鍵,都可以保證惟一性。一個等值查詢,最多隻能返回一條記錄,並且新的相同取值的記錄,必定不會在新插入進來,所以也就避免了GAP鎖的使用。其實,針對此問題,還有一個更深刻的問題:若是組合5、組合六下,針對SQL:select * from t1 where id = 10 for update; 第一次查詢,沒有找到知足查詢條件的記錄,那麼GAP鎖是否還可以省略?此問題留給你們思考。

結論:Repeatable Read隔離級別下,id列上有一個非惟一索引,對應SQL:delete from t1 where id = 10; 首先,經過id索引定位到第一條知足查詢條件的記錄,加記錄上的X鎖,加GAP上的GAP鎖,而後加主鍵聚簇索引上的記錄X鎖,而後返回;而後讀取下一條,重複進行。直至進行到第一條不知足條件的記錄[11,f],此時,不須要加記錄X鎖,可是仍舊須要加GAP鎖,最後返回結束。

何時會取得gap lock或nextkey lock 這和隔離級別有關,只在REPEATABLE READ或以上的隔離級別下的特定操做纔會取得gap lock或nextkey lock。

組合八:id無索引+RR

  組合八,Repeatable Read隔離級別下的最後一種狀況,id列上沒有索引。此時SQL:delete from t1 where id = 10; 沒有其餘的路徑能夠選擇,只能進行全表掃描。最終的加鎖狀況,以下圖所示:   

  如圖,這是一個很恐怖的現象。首先,聚簇索引上的全部記錄,都被加上了X鎖。其次,聚簇索引每條記錄間的間隙(GAP),也同時被加上了GAP鎖。這個示例表,只有6條記錄,一共須要6個記錄鎖,7個GAP鎖。試想,若是表上有1000萬條記錄呢?

  在這種狀況下,這個表上,除了不加鎖的快照度,其餘任何加鎖的併發SQL,均不能執行,不能更新,不能刪除,不能插入,全表被鎖死。

  固然,跟組合四:[id無索引, Read Committed]相似,這個狀況下,MySQL也作了一些優化,就是所謂的semi-consistent read。semi-consistent read開啓的狀況下,對於不知足查詢條件的記錄,MySQL會提早放鎖。針對上面的這個用例,就是除了記錄[d,10],[g,10]以外,全部的記錄鎖都會被釋放,同時不加GAP鎖。semi-consistent read如何觸發:要麼是read committed隔離級別;要麼是Repeatable Read隔離級別,同時設置了innodb_locks_unsafe_for_binlog 參數。更詳細的關於semi-consistent read的介紹,可參考我以前的一篇博客:MySQL+InnoDB semi-consitent read原理及實現分析

結論:在Repeatable Read隔離級別下,若是進行全表掃描的當前讀,那麼會鎖上表中的全部記錄,同時會鎖上聚簇索引內的全部GAP,杜絕全部的併發 更新/刪除/插入 操做。固然,也能夠經過觸發semi-consistent read,來緩解加鎖開銷與併發影響,可是semi-consistent read自己也會帶來其餘問題,不建議使用。

組合九:Serializable

  針對前面提到的簡單的SQL,最後一個狀況:Serializable隔離級別。對於SQL2:delete from t1 where id = 10; 來講,Serializable隔離級別與Repeatable Read隔離級別徹底一致,所以不作介紹。

  Serializable隔離級別,影響的是SQL1:select * from t1 where id = 10; 這條SQL,在RC,RR隔離級別下,都是快照讀,不加鎖。可是在Serializable隔離級別,SQL1會加讀鎖,也就是說快照讀不復存在,MVCC併發控制降級爲Lock-Based CC。

結論:在MySQL/InnoDB中,所謂的讀不加鎖,並不適用於全部的狀況,而是隔離級別相關的。Serializable隔離級別,讀不加鎖就再也不成立,全部的讀操做,都是當前讀。

5、死鎖案例

1. 不一樣表相同記錄行鎖衝突

這種狀況很好理解,事務A和事務B操做兩張表,但出現循環等待鎖狀況。

2. 相同表記錄行鎖衝突

這種狀況比較常見,以前遇到兩個job在執行數據批量更新時,jobA處理的的id列表爲[1,2,3,4],而job處理的id列表爲[8,9,10,4,2],這樣就形成了死鎖。

3. 不一樣索引鎖衝突

這種狀況比較隱晦,事務A在執行時,除了在二級索引加鎖外,還會在聚簇索引上加鎖,在聚簇索引上加鎖的順序是[1,4,2,3,5],而事務B執行時,只在聚簇索引上加鎖,加鎖順序是[1,2,3,4,5],這樣就形成了死鎖的可能性。

4. gap鎖衝突

innodb在RR級別下,以下的狀況也會產生死鎖,比較隱晦。不清楚的同窗能夠自行根據上節的gap鎖原理分析下。

6、如何儘量避免死鎖

  1. 以固定的順序訪問表和行。好比對第2節兩個job批量更新的情形,簡單方法是對id列表先排序,後執行,這樣就避免了交叉等待鎖的情形;又好比對於3.1節的情形,將兩個事務的sql順序調整爲一致,也能避免死鎖。
  2. 大事務拆小。大事務更傾向於死鎖,若是業務容許,將大事務拆小。
  3. 在同一個事務中,儘量作到一次鎖定所須要的全部資源,減小死鎖機率。
  4. 下降隔離級別。若是業務容許,將隔離級別調低也是較好的選擇,好比將隔離級別從RR調整爲RC,能夠避免掉不少由於gap鎖形成的死鎖。
  5. 爲表添加合理的索引。能夠看到若是不走索引將會爲表的每一行記錄添加上鎖,死鎖的機率大大增大。=

7、如何查看鎖

從InnoDB1.0開始,在INFORMATION_SCHEMA架構下添加了表INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS。(詳情見附錄)經過這三張表,用戶能夠更簡單地監控當前事務並分析可能存在的鎖問題。

#全局分析系統上中行鎖的爭奪狀況
show status like 'innodb_row_lock%';
#查看事務
SELECT * FROM information_schema.INNODB_TRX;
#查看鎖
SELECT * FROM information_schema.INNODB_LOCKS;
#查看鎖等待狀況
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
#經過聯合查詢能夠比較直觀的查看哪一個事務阻塞了哪一個事務
SELECT r.trx_id              '等待事務ID',
       r.trx_mysql_thread_id '等待線程ID',
       r.trx_query           '等待事務運行語句',
       b.trx_id              '阻塞事務ID',
       b.trx_mysql_thread_id '阻塞線程ID',
       b.trx_query           '阻塞事務運行語句'
FROM information_schema.innodb_lock_waits w
         INNER JOIN information_schema.innodb_trx b
                    ON b.trx_id = w.blocking_trx_id
         INNER JOIN information_schema.innodb_trx r
                    ON r.trx_id = w.requesting_trx_id;
複製代碼

8、mysql是如何預防死鎖的?

innodb_lock_wait_timeout 等待鎖超時回滾事務

直觀方法是在兩個事務相互等待時,當一個等待時間超過設置的某一閥值時,對其中一個事務進行回滾,另外一個事務就能繼續執行。

wait-for graph算法來主動進行死鎖檢測

每當加鎖請求沒法當即知足須要並進入等待時,wait-for graph算法都會被觸發。

wait-for graph要求數據庫保存如下兩種信息:

  • 鎖的信息鏈表

  • 事務等待鏈表

經過上述鏈表能夠構造出一張圖,而在這個圖中若存在迴路,就表明存在死鎖,所以資源間相互發生等待。在wait-for graph中,事務爲圖中的節點。而在圖中,事務T1指向T2邊的定義爲:

  • 事務T1等待事務T2所佔用的資源

  • 事務T1最終等待T2所佔用的資源,也就是事務之間在等待相同的資源,而事務T1發生在事務T2的後面

示例事務狀態和鎖的信息

在Transaction Wait Lists中能夠看到共有4個事務t一、t二、t三、t4,故在wait-for graph中應有4個節點。而事務t2對row1佔用x鎖,事務t1對row2佔用s鎖。事務t1須要等待事務t2中row1的資源,所以在wait-for graph中有條邊從節點t1指向節點t2。事務t2須要等待事務t一、t4所佔用的row2對象,故而存在節點t2到節點t一、t4的邊。一樣,存在節點t3到節點t一、t二、t4的邊,所以最終的wait-for graph以下圖所示。

ps:若存在則有死鎖,一般來講InnoDB存儲引擎選擇回滾undo量最小的事務並重新開始

附錄

INNODB_ROW_LOCK

列名 描述
innodb_row_lock_current_waits 當前正在等待鎖定的數量
innodb_row_lock_time 從系統啓動到如今鎖定總時間長度
innodb_row_lock_time_avg 每次等待所花平均時間
innodb_row_lock_time_max 從系統啓動到如今等待最常的一次所花的時間
innodb_row_lock_waits 系統啓動後到如今總共等待的次數;直接決定優化的方向和策略

INNODB_TRX

提供有關當前正在內部執行的每一個事務的信息 InnoDB,包括事務是否在等待鎖定,事務什麼時候啓動以及事務正在執行的SQL語句(若是有)。詳見dev.mysql.com/doc/refman/…

列名 描述
TRX_ID 事務Id
TRX_WEIGHT 事務的權重,反映(但不必定是確切的計數)更改的行數和事務鎖定的行數。要解決死鎖,請 InnoDB``選擇權重最小的事務做爲回滾的「 受害者 」。不管更改和鎖定行的數量如何,已更改非事務表的事務都被認爲比其餘事務更重。
TRX_STATE 事務執行狀態。容許值是 RUNNING,LOCK WAIT, ROLLING BACK,和 COMMITTING
TRX_STARTED 交易開始時間。
TRX_REQUESTED_LOCK_ID 事務當前正在等待的鎖的ID,若是TRX_STATE是LOCK WAIT; 不然NULL``。
TRX_WAIT_STARTED 交易開始等待鎖定的時間,若是 TRX_STATE是LOCK WAIT; 不然NULL``。
TRX_MYSQL_THREAD_ID MySQL線程ID,與show processlist中的ID值相對應
TRX_QUERY 事務正在執行的SQL語句
TRX_OPERATION_STATE 交易的當前操做,若是有的話; 不然 NULL``。
TRX_TABLES_IN_USE InnoDB``處理此事務的當前SQL語句時使用 的表數。
TRX_TABLES_LOCKED InnoDB``當前SQL語句具備行鎖定 的表的數量。(由於這些是行鎖,而不是表鎖,因此一般仍能夠經過多個事務讀取和寫入表,儘管某些行被鎖定。)
TRX_LOCK_STRUCTS 事務保留的鎖數。
TRX_LOCK_MEMORY_BYTES 內存中此事務的鎖結構佔用的總大小
TRX_ROWS_LOCKED 此交易鎖定的大體數字或行數。該值可能包括實際存在但對事務不可見的刪除標記行
TRX_ROWS_MODIFIED 此事務中已修改和插入的行數。
TRX_CONCURRENCY_TICKETS 一個值,指示當前事務在被換出以前能夠執行多少工做
TRX_ISOLATION_LEVEL 當前事務的隔離級別。
TRX_UNIQUE_CHECKS 是否爲當前事務打開或關閉惟一檢查。例如,在批量數據加載期間可能會關閉它們
TRX_FOREIGN_KEY_CHECKS 是否爲當前事務打開或關閉外鍵檢查。例如,在批量數據加載期間可能會關閉它們
TRX_LAST_FOREIGN_KEY_ERROR 最後一個外鍵錯誤的詳細錯誤消息(若是有); 不然NULL``
TRX_ADAPTIVE_HASH_LATCHED 自適應哈希索引是否被當前事務鎖定。當自適應哈希索引搜索系統被分區時,單個事務不會鎖定整個自適應哈希索引。自適應哈希索引分區由innodb_adaptive_hash_index_parts``,默認設置爲8。
TRX_ADAPTIVE_HASH_TIMEOUT 是否當即爲自適應哈希索引放棄搜索鎖存器,或者在MySQL的調用之間保留它。當沒有自適應哈希索引爭用時,該值保持爲零,語句保留鎖存器直到它們完成。在爭用期間,它倒計時到零,而且語句在每次行查找後當即釋放鎖存器。當自適應散列索引搜索系統被分區(受控制 innodb_adaptive_hash_index_parts``)時,該值保持爲0。
TRX_IS_READ_ONLY 值爲1表示事務是隻讀的。
TRX_AUTOCOMMIT_NON_LOCKING 值爲1表示事務是 SELECT](https://dev.mysql.com/doc/refman/5.7/en/select.html)不使用FOR UPDATEor或 LOCK IN SHARED MODE子句的語句,而且正在執行, [autocommit所以事務將僅包含此一個語句。當此列和TRX_IS_READ_ONLY都爲1時,InnoDB優化事務以減小與更改表數據的事務關聯的開銷

INNODB_LOCKS

提供有關InnoDB 事務已請求但還沒有獲取的每一個鎖的信息,以及事務持有的阻止另外一個事務的每一個鎖。詳見dev.mysql.com/doc/refman/…

列名 描述
LOCK_ID 一個惟一的鎖ID號,內部爲 InnoDB``。
LOCK_TRX_ID 持有鎖的交易的ID
LOCK_MODE 如何請求鎖定。容許鎖定模式描述符 S,X, IS,IX, GAP,AUTO_INC,和 UNKNOWN``。鎖定模式描述符能夠組合使用以識別特定的鎖定模式。
LOCK_TYPE 鎖的類型
LOCK_TABLE 已鎖定或包含鎖定記錄的表的名稱
LOCK_INDEX 索引的名稱,若是LOCK_TYPE是 RECORD; 不然NULL
LOCK_SPACE 鎖定記錄的表空間ID,若是 LOCK_TYPE是RECORD; 不然NULL``
LOCK_PAGE 鎖定記錄的頁碼,若是 LOCK_TYPE是RECORD; 不然NULL``。
LOCK_REC 頁面內鎖定記錄的堆號,若是 LOCK_TYPE是RECORD; 不然NULL``。
LOCK_DATA 與鎖相關的數據(若是有)。若是 LOCK_TYPE是RECORD,是鎖定的記錄的主鍵值,不然NULL。此列包含鎖定行中主鍵列的值,格式爲有效的SQL字符串。若是沒有主鍵,LOCK_DATA則是惟一的InnoDB內部行ID號。若是對鍵值或範圍高於索引中的最大值的間隙鎖定,則LOCK_DATA 報告_supremum_ pseudo-record。當包含鎖定記錄的頁面不在緩衝池中時(若是在保持鎖定時將其分頁到磁盤),InnoDB不從磁盤獲取頁面,以免沒必要要的磁盤操做。相反, LOCK_DATA設置爲 NULL``。

INNODB_LOCK_WAITS

包含每一個被阻止InnoDB 事務的一個或多個行,指示它已請求的鎖以及阻止該請求的任何鎖。詳見dev.mysql.com/doc/refman/…

列名 描述
REQUESTING_TRX_ID 請求(阻止)事務的ID。
REQUESTED_LOCK_ID 事務正在等待的鎖的ID。
BLOCKING_TRX_ID 阻止事務的ID。
BLOCKING_LOCK_ID 由阻止另外一個事務繼續進行的事務所持有的鎖的ID

引用文獻

《MySQL技術內幕:InnoDB存儲引擎》

何登成MySQL 加鎖處理分析

Mysql加鎖過程詳解

數據庫事務和鎖(三)

針對MySQL死鎖問題的思路分析

相關文章
相關標籤/搜索