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