記錄工作遇到的死鎖問題(Lock wait timeout exceeded; try restarting transaction)

1.問題背景

剛來新公司不久,對業務還不太熟悉,所以領導先安排我維護原有系統。大概介紹下項目背景,項目分為核心業務部分在項目A中,與第三方交互的業務在項目B中,前端發起請求調用A項目接口,並在A項目中調用B項目接口,並在B項目中調用第三方獲取數據(原有系統這樣設計的)。

獲取到第三方數據后判斷數據庫中是否有該記錄(有唯一鍵),如有則執行更新操作,沒有則新增。並且如果第三方認為該數據已失效,需要從數據庫中刪除(邏輯刪除),並返回第三方刪除成功回調,後續便不會再查到已失效的數據。

對應流程圖如下

在代碼處理中對整個過程加事務@Transactional註解,即在對數據進行刪除(邏輯刪除,實際執行update語句)時會根據唯一索引對該行加鎖。在生成環境B項目頻繁出現Lock wait timeout exceeded; try restarting transaction 異常,經排查定位到該功能代碼,排查代碼發現該功能有如下代碼

有經驗的同學應該已經看出問題所在,這裏將全局異常捕獲,記錄錯誤日誌,但問題就出在catch這裏,由於異常被catch吞噬,@Transactional無法拿到異常,所以不會執行rollback回滾,導致一直佔用數據庫行鎖。(這裏的異常是調用第三方接口失敗,由於調用太頻繁,第三方接口崩潰,這裏後續也做了併發控制) 所以後續事務在執行更新該行記錄時由於得不到鎖而等待失敗,就報了Lock wait timeout exceeded; try restarting transaction 異常。知道了問題出在什麼地方,解決起來也就簡單了,在catch中再將異常主動拋出即可 。即 throw e

  

2.問題影響

由於該接口是在核心項目A中有客戶端發起調用,並在A項目中調用B項目,由於B項目死鎖無法返回結果,導致A項目前端大量請求阻塞,由於tomcat支持的請求線程數有限,該問題直接導致A服務宕機。影響較為嚴重。

 

3.如何解決

下面說下該問題解決思路,由於A項目宕機,在服務器日誌中可以看到大量上述異常信息,Lock wait說明出現了鎖問題。

  a.使用 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;查看當前事務,使用SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;查看當前鎖定的事務,使用SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;查看當前等鎖的事務。使用以上三個sql基本能定位到代碼所在位置。

  b.定位到代碼后,就要看具體的代碼問題了,導致異常沒有回滾的原因很多。這裏說一個注意事項,使用@Transactional註解,默認只會對RuntimeException進行回滾,而對IOException和SQLException不會觸發回滾。如果要對兩個非運行時異常進行回滾,需要在@Transactional中加入@Transactional( rollbackForClassName = {“IOException”,”SQLException”})或對全局異常Exception做回滾,配置為@Transactional(rollbackFor = Exception.class)。又或者捕獲IOException後手動拋出一個RuntimeException

  

總結

  以上為博主在實際工作中遇到的問題,這裏記錄一下方便以後遇到類似問題可以快速定位並解決問題。也希望能對大家有幫助。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!