Mysql報Deadlock found when trying to get lock 問題解決


Mysql報Deadlock found when trying to get lock; try restarting transaction問題解決

問題發生場景

今天記錄一下最近項目中遇到的一個問題,前幾天在部署項目后,在線上運行過程中,突然報了入下這樣的錯誤,從報錯信息中我們可以看到,是mysql在執行update操作的時候報了一個死鎖的問題,今天解決了,特此記錄一下.
在這里插入圖片描述

Mysql鎖類型分析
MySQL有三種鎖的級別:頁級、表級、行級,這個地方我遇到的問題是來自於行級鎖,所以重點說一下。

類型 特性
表級鎖 (table-level locking) 開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。
行級鎖 (row-level locking) 開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。
頁面鎖 (page-level locking) 開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一
  • 行級鎖在使用的時候並不是直接鎖掉這行記錄,而是鎖索引
  • 如果一條sql用到了主鍵索引(mysql主鍵自帶索引),mysql會鎖住主鍵索引;
  • 如果一條sql操作了非主鍵索引,mysql會先鎖住非主鍵索引,再鎖定主鍵索引

問題排查過程

通過上面log日志中的報錯信息,能很快確認報錯的准確位置,

這個地方是執行了一個update的操作,我找到了了這個表,看了一下這個表的索引是有三個,兩個非主鍵索引,一個主鍵索引.
在這里插入圖片描述
果然,在圖中這兩條索引在那個update語句中都有進行的操作,具體如下

然后我又找了一下有可能會跟這條語句發生沖突的地方,果然在這個報錯信息的上面,執行了一條這樣的sql,這兩條sql執行的間隔僅僅不超過1毫秒

根據上面所說的,如果一條sql用到了主鍵索引(mysql主鍵自帶索引),mysql會鎖住主鍵索引;
如果一條sql操作了非主鍵索引,mysql會先鎖住非主鍵索引,再鎖定主鍵索引.
因此sql(2)在使用的時候用到了schedu_id這個非主鍵索引,還需要鎖定主鍵索引,然而此時sql(1)開始執行
,然后鎖定了主鍵索引,但是在set操作中還用到了schedu_id這個非主鍵索引,但是這個索引在sql(1)執行的時候還在處於被鎖的狀態,因此兩條sql就出現了對索引資源的競爭,造成了死鎖.

解決方法

這個地方,代碼的問題需要根據情況自己去修改,可以試着把索引去掉(有風險),或者在進行update的時候盡量避開非主鍵索引,我這里記錄一下被鎖后應該怎么去解決的方法,首先先用sql查詢一下mysql的事務處理表

select * from information_schema.INNODB_TRX

正常情況下的狀態都是RUNNING,但是在被鎖之后就會變成LOCK WAIT ,一旦出現這種情況,就得殺死這個進程,如果進程殺不死就只能重啟Mysql服務了
殺死進程

kill 進程ID

然后系統就能繼續運行了,

經驗教訓

無論前台后台的程序,都不應該存在僅根據非主鍵的幾個字段一查就要update/delete的場景。即使有,也應該改為先把要更新的記錄查出來然后逐條按主鍵id更新。


版權聲明:本文為CSDN博主「光頭2強」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_44240587/article/details/108400666


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM