[數據庫]記一次數據庫死鎖


業務新上了一個功能,在發布的過程中,系統報出了數據庫死鎖異常:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

死鎖發生在一個事務中,事務對多個表進行了操作。在報錯日志中,死鎖發生在tableA與tableB。一開始懷疑此次發布的某個改動中對上面這兩張表新增了select或update操作。將注意力用在排查這個問題上。排查后發現沒有相關的變更,又猜測是否是由於更改造成並發請求進來,接口原來是有加分布式鎖的,需求更改中縮小了分布式鎖的粒度,確實是有可能造成並發請求。但很快又否定了,秒殺場景下的並發量尚且不會發生死鎖,何況是這個接口?覺得問題應該別有所在。先回滾了需求后,聯系dba執行了命令SHOW ENGINE INNODB STATUS將死鎖日志拉取了出來:

從死鎖日志可以看到事務(1)TRANSACTION嘗試更新表A,等待表A的鎖(1)WATING FOR THIS LOCK TO BE GRANTED.但此時另外一個事務(2)TRANSACTION已經持有了表A的鎖:(2)HOLDS THE LOCK(S),同時也在等待表B的鎖(2)WATING FOR THIS LOCK TO BE GRANTED. 情況可能如下所示:

事務(1) 事務(2)
持有表1的寫鎖,並更新了表1
等待表1的寫鎖
等待表2的寫鎖

由於事務2一直都獲取不到表2的寫鎖,事務2無法提交,因此事務2持有的表1鎖沒有釋放(在事務執行過程中,如果有加鎖操作,這個鎖需要等事務提交時釋放),導致事務1一直在等待表1的寫鎖,從而最終導致死鎖。那么表2的寫鎖被哪個事務持有了?有沒有可能是事務1?也即是下面這種情況:

事務(1) 事務(2)
持有表2的寫鎖,並更新了表2
持有表1的寫鎖,並更新了表1
等待表1的寫鎖
等待表2的寫鎖

由於更新的是同一個用戶的同一行記錄,這種情況可能在sql執行順序不一致所導致,所以對比了需求變更前后的事務邏輯,果然發現了端倪:

變更前:

事務開始
「
	更新表1
	更新表2
」
事務提交

變更后:

事務開始
「
	更新表2
	更新表1
」
事務提交

在發布的過程中,有部分機器的代碼處於變更前,有部分機器的代碼處於變更后,最終導致了上述的死鎖問題。此時原因已經明了,但是疑惑的是為什么死鎖出現時馬上就報錯,不會進行等待?查閱文檔發現:死鎖檢測開了后,發生死鎖會立馬回滾。死鎖檢測關閉,鎖等待超時時間這個設置才會生效:


免責聲明!

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



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