MySQL(InnoDB)是如何處理死鎖的

MySQL(InnoDB)是如何處理死鎖的

1、什麼是死鎖

官方定義以下:兩個事務都持有對方須要的鎖,而且在等待對方釋放,而且雙方都不會釋放本身的鎖。mysql

這個就比如你有一我的質,對方有一我的質,大家倆去談判說換人。你讓對面放人,對面讓你放人。sql

死鎖的造成

2、爲何會造成死鎖

看到這裏,也許你會有這樣的疑問,事務和談判不同,爲何事務不能使用完鎖以後立馬釋放呢?竟然還要操做完了以後一直持有鎖?這就涉及到 MySQL 的併發控制了。併發

MySQL的併發控制有兩種方式,一個是 MVCC,一個是兩階段鎖協議。那麼爲何要併發控制呢?是由於多個用戶同時操做 MySQL 的時候,爲了提升併發性能而且要求如同多個用戶的請求過來以後如同串行執行的同樣(可串行化調度)。具體的併發控制這裏再也不展開。我們繼續深刻討論兩階段鎖協議。高併發

兩階段鎖協議(2PL)

官方定義:性能

兩階段鎖協議是指全部事務必須分兩個階段對數據加鎖和解鎖,在對任何數據進行讀、寫操做以前,事務首先要得到對該數據的封鎖;在釋放一個封鎖以後,事務再也不申請和得到任何其餘封鎖。.net

對應到 MySQL 上分爲兩個階段:命令行

  1. 擴展階段(事務開始後,commit 以前):獲取鎖
  2. 收縮階段(commit 以後):釋放鎖

就是說呢,只有遵循兩段鎖協議,才能實現 可串行化調度調試

可是兩階段鎖協議不要求事務必須一次將全部須要使用的數據加鎖,而且在加鎖階段沒有順序要求,因此這種併發控制方式會造成死鎖。日誌

3、MySQL 如何處理死鎖?

MySQL有兩種死鎖處理方式:code

  1. 等待,直到超時(innodb_lock_wait_timeout=50s)。
  2. 發起死鎖檢測,主動回滾一條事務,讓其餘事務繼續執行(innodb_deadlock_detect=on)。

因爲性能緣由,通常都是使用死鎖檢測來進行處理死鎖。

死鎖檢測

死鎖檢測的原理是構建一個以事務爲頂點、鎖爲邊的有向圖,判斷有向圖是否存在環,存在即有死鎖。

回滾

檢測到死鎖以後,選擇插入更新或者刪除的行數最少的事務回滾,基於 INFORMATION_SCHEMA.INNODB_TRX 表中的 trx_weight 字段來判斷。

4、如何避免發生死鎖

收集死鎖信息:

  1. 利用命令 SHOW ENGINE INNODB STATUS查看死鎖緣由。
  2. 調試階段開啓 innodb_print_all_deadlocks,收集全部死鎖日誌。

減小死鎖:

  1. 使用事務,不使用 lock tables
  2. 保證沒有長事務。
  3. 操做完以後當即提交事務,特別是在交互式命令行中。
  4. 若是在用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),嘗試下降隔離級別。
  5. 修改多個表或者多個行的時候,將修改的順序保持一致
  6. 建立索引,可使建立的鎖更少。
  7. 最好不要用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE)
  8. 若是上述都沒法解決問題,那麼嘗試使用 lock tables t1, t2, t3 鎖多張表
相關文章
相關標籤/搜索