剛來新公司不久,對業務還不太熟悉,因此領導先安排我維護原有系統。大概介紹下項目背景,項目分爲核心業務部分在項目A中,與第三方交互的業務在項目B中,前端發起請求調用A項目接口,並在A項目中調用B項目接口,並在B項目中調用第三方獲取數據(原有系統這樣設計的)。前端
獲取到第三方數據後判斷數據庫中是否有該記錄(有惟一鍵),若有則執行更新操做,沒有則新增。而且若是第三方認爲該數據已失效,須要從數據庫中刪除(邏輯刪除),並返回第三方刪除成功回調,後續便不會再查到已失效的數據。sql
對應流程圖以下數據庫
在代碼處理中對整個過程加事務@Transactional註解,即在對數據進行刪除(邏輯刪除,實際執行update語句)時會根據惟一索引對該行加鎖。在生成環境B項目頻繁出現Lock wait timeout exceeded; try restarting transaction 異常,經排查定位到該功能代碼,排查代碼發現該功能有以下代碼tomcat
有經驗的同窗應該已經看出問題所在,這裏將全局異常捕獲,記錄錯誤日誌,但問題就出在catch這裏,因爲異常被catch吞噬,@Transactional沒法拿到異常,因此不會執行rollback回滾,致使一直佔用數據庫行鎖。(這裏的異常是調用第三方接口失敗,因爲調用太頻繁,第三方接口崩潰,這裏後續也作了併發控制) 因此後續事務在執行更新該行記錄時因爲得不到鎖而等待失敗,就報了Lock wait timeout exceeded; try restarting transaction 異常。服務器
因爲該接口是在覈心項目A中有客戶端發起調用,並在A項目中調用B項目,因爲B項目死鎖沒法返回結果,致使A項目前端大量請求阻塞,因爲tomcat支持的請求線程數有限,該問題直接致使A服務宕機。影響較爲嚴重。併發
下面說下該問題解決思路,因爲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後手動拋出一個RuntimeExceptionrest
以上爲博主在實際工做中遇到的問題,這裏記錄一下方便之後遇到相似問題能夠快速定位並解決問題。也但願能對你們有幫助。日誌