MySQL相關(九)- 死鎖的發生和避免

前言

在上一篇章咱們講了行級鎖的原理,你們看到這裏的話應該也瞭解得差很少了,咱們這裏再來說講經過對行級鎖的認識學習以後,應該注意和避免的點。php

在咱們使用鎖的時候,有一個問題是須要注意和避免的,咱們知道,排它鎖有互斥的特性。一個事務或者說一個線程持有鎖的時候,會阻止其餘的線程獲取鎖,這個時候會形成阻塞等待,若是循環等待,會有可能形成死鎖mysql

這個問題咱們須要從幾個方面來分析,一個是鎖爲何不釋放,第二個是被阻塞了怎麼辦,第三個死鎖是怎麼發生的,怎麼避免。咱們且看正文部分。程序員

老規矩,先上飛機票:面試

  1. MySQL相關(一)- 一條查詢語句是如何執行的
  2. MySQL相關(二)- 一條更新語句是如何執行的
  3. MySQL相關(番外篇)- innodb 邏輯存儲結構
  4. MySQL相關(三)- 索引數據模型推演及 B+Tree 的詳細介紹
  5. MySQL相關(四)- 性能優化關鍵點索引
  6. MySQL相關(五)- 事務特性及隔離級別的詳細介紹
  7. MySQL相關(六)- 事務隔離級別的實現方案(MVCC)
  8. MySQL相關(七)- innodb 鎖的介紹及使用
  9. MySQL相關(八)- innodb行級鎖深刻剖析

前面提到的腦圖以下,想要完整高清圖片能夠到微信個人公衆號下【6曦軒】下回復 MySQL 腦圖獲取: 在這裏插入圖片描述算法

正文

死鎖

鎖的釋放與阻塞

回顧:鎖何時釋放?sql

事務結束(commit,rollback);客戶端鏈接斷開。數據庫

若是一個事務一直未釋放鎖,其餘事務會被阻塞多久?會不會永遠等待下去?若是是,在併發訪問比較高的狀況下,若是大量事務因沒法當即得到所需的鎖而掛起,會佔用大量計算機資源,形成嚴重性能問題,甚至拖跨數據庫。性能優化

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction MySQL 有一個參數來控制獲取鎖的等待時間,默認是 50 秒。微信

show VARIABLES like 'innodb_lock_wait_timeout';

在這裏插入圖片描述

對於死鎖,是不管等多久都不能獲取到鎖的,這種狀況,也須要等待 50 秒鐘嗎?那架構

不是白白浪費了 50 秒鐘的時間嗎?

咱們先來看一下何時會發生死鎖。

死鎖的發生和檢測

死鎖演示:

Session 1 Session 2
begin;<br/>select * from t2 where id =1 for update;
- begin;<br />delete from t2 where id =4 ;
update t2 set name= '4d' where id =4 ;
- delete from t2 where id =1 ;

在第一個事務中,檢測到了死鎖,立刻退出了,第二個事務得到了鎖,不須要等待 50 秒:

[Err] 1213 - Deadlock found when trying to get lock; try restarting transaction

爲何能夠直接檢測到呢?是由於死鎖的發生須要知足必定的條件,因此在發生死鎖時,InnoDB 通常都能經過算法(wait-for graph)自動檢測到。

那麼死鎖須要知足什麼條件?死鎖的產生條件:

由於鎖自己是互斥的 (1)同一時刻只能有一個事務持有這把鎖; (2)其餘的事務須要在這個事務釋放鎖以後才能獲取鎖,而不能夠強行剝奪; (3)當多個事務造成等待環路的時候,即發生死鎖。

舉例:

理髮店有兩個總監。一個負責剪頭的 Tony 總監,一個負責洗頭的 Kelvin 總監。

Tony 不能同時給兩我的剪頭,這個就叫互斥。

Tony 在給別人在剪頭的時候,你不能讓他停下來幫你剪頭,這個叫不能強行剝奪。若是 Tony 的客戶對 Kelvin 總監說:你不幫我洗頭我怎麼剪頭?Kelvin 的客戶對 Tony 總監說:你不幫我剪頭我怎麼洗頭?這個就叫造成等待環路。

若是鎖一直沒有釋放,就有可能形成大量阻塞或者發生死鎖,形成系統吞吐量降低,這時候就要查看是哪些事務持有了鎖。

查看鎖信息(日誌)

SHOW STATUS 命令中,包括了一些行鎖的信息:

show status like 'innodb_row_lock_%';

在這裏插入圖片描述

  • Innodb_row_lock_current_waits:當前正在等待鎖定的數量;
  • Innodb_row_lock_time :從系統啓動到如今鎖定的總時間長度,單位 ms;
  • Innodb_row_lock_time_avg :每次等待所花平均時間;
  • Innodb_row_lock_time_max:從系統啓動到如今等待最長的一次所花的時間;
  • Innodb_row_lock_waits :從系統啓動到如今總共等待的次數。

SHOW 命令是一個概要信息。InnoDB 還提供了三張表來分析事務與鎖的狀況:

select * from information_schema.INNODB_TRX;	-- 當前運行的全部事務 ,還有具體的語句

在這裏插入圖片描述

select * from information_schema.INNODB_LOCKS;	--  當前出現的鎖

在這裏插入圖片描述

select * from information_schema.INNODB_LOCK_WAITS;	--  鎖等待的對應關係

在這裏插入圖片描述

找出持有鎖的事務以後呢?

若是一個事務長時間持有鎖不釋放,能夠 kill 事務對應的線程 ID ,也就是 INNODB_TRX 表中的 trx_mysql_thread_id,例如執行 kill 4,kill 7,kill 8。

固然,死鎖的問題不能每次都靠 kill 線程來解決,這是治標不治本的行爲。咱們應該儘可能在應用端,也就是在編碼的過程當中避免。

有哪些能夠避免死鎖的方法呢?

死鎖的避免

  1. 在程序中,操做多張表時,儘可能以相同的順序來訪問(避免造成等待環路);
  2. 批量操做單張表數據的時候,先對數據進行排序(避免造成等待環路);
  3. 申請足夠級別的鎖,若是要操做數據,就申請排它鎖;
  4. 儘可能使用索引訪問數據,避免沒有 where 條件的操做,避免鎖表;
  5. 若是能夠,大事務化成小事務;
  6. 使用等值查詢而不是範圍查詢查詢數據,命中記錄,避免間隙鎖對併發的影響。

By the way

有問題?能夠給我留言或私聊 有收穫?那就順手點個讚唄~

固然,也能夠到個人公衆號下「6曦軒」,

回覆「學習」,便可領取一份 【Java工程師進階架構師的視頻教程】~

回覆「面試」,能夠得到: 【本人嘔心瀝血整理的 Java 面試題】

回覆「MySQL腦圖」,能夠得到 【MySQL 知識點梳理高清腦圖】

因爲我咧,科班出身的程序員,php,Android以及硬件方面都作過,不過最後仍是選擇專一於作 Java,因此有啥問題能夠到公衆號提問討論(技術情感傾訴均可以哈哈哈),看到的話會盡快回復,但願能夠跟你們共同窗習進步,關於服務端架構,Java 核心知識解析,職業生涯,面試總結等文章會不按期堅持推送輸出,歡迎你們關注~~~

在這裏插入圖片描述

相關文章
相關標籤/搜索