記一次數據庫死鎖

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

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將死鎖日誌拉取了出來:sql

從死鎖日誌能夠看到事務(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執行順序不一致所致使,因此對比了需求變動先後的事務邏輯,果真發現了端倪:分佈式

變動前:rest

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

變動後:日誌

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

在發佈的過程當中,有部分機器的代碼處於變動前,有部分機器的代碼處於變動後,最終致使了上述的死鎖問題。此時緣由已經明瞭,可是疑惑的是爲何死鎖出現時立刻就報錯,不會進行等待?查閱文檔發現:死鎖檢測開了後,發生死鎖會立馬回滾。死鎖檢測關閉,鎖等待超時時間這個設置纔會生效:code

相關文章
相關標籤/搜索