一次線上死鎖問題

這兩天遇到了一個(gè)死鎖的問題,下面是errorLog打的報(bào)錯(cuò)信息

經(jīng)過網(wǎng)上資料查詢,原因?yàn)椋篠pring 事務(wù)嵌套造成死鎖。

該異常為一個(gè)service中調(diào)用了另一個(gè)service,兩個(gè)service對同一表進(jìn)行操作,造成事務(wù)嵌套,從而死鎖。

解決辦法:在當(dāng)前方法前加入@Transactional(propagation=Propagation.SUPPORTS)


這個(gè)參數(shù)的作用是:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。

如果其他bean調(diào)用這個(gè)方法,在其他bean中聲明了事務(wù),那就用事務(wù),如果其他bean中沒有聲明事務(wù),那就不用事務(wù)。?這個(gè)不是很理解


以上都是網(wǎng)上查詢該報(bào)錯(cuò)對應(yīng)實(shí)際應(yīng)用的解決方案,由于這臺服務(wù)器的mysql版本是5.1的,information_schema還沒有加入innodb事務(wù)相關(guān)的表查詢,升級到5.6版本以后可以查詢INNODB_LOCKS、INNODB_TRX、INNODB_LOCK_WAITS;

于是我只能查mysql的innodb運(yùn)行狀態(tài),

語句是:SHOW ENGINE INNODB STATUS\G;

下面是死鎖的部分信息 可以看到player_general_military這個(gè)表產(chǎn)生了死鎖 被兩個(gè)不同的線程持有 一個(gè)是增加exp?一個(gè)是重置evoke_buff



我們知道m(xù)ysql 事務(wù)具有acid屬性,分別是代表原子性,隔離性,一致性,持久性。

根據(jù)原子性可以知道事務(wù)操作是不可再分的,每個(gè)事務(wù)要么全部成功要么全部失敗,通過隔離性可以知道:事務(wù)之間不會相互影響。

但是本次為什么還出現(xiàn)了并發(fā)事務(wù)出現(xiàn)了死鎖問題呢?

根據(jù)死鎖日志可以提取幾個(gè)有用信息:


首先mysql默認(rèn)的隔離級別是可重復(fù)讀,事務(wù)未提交之前總是讀到相同的記錄,該隔離級別就是為了避免讀已提交出現(xiàn)的幻讀現(xiàn)象,采用的是GAP間隙鎖實(shí)現(xiàn)。

根據(jù)上表可以得到信息,兩個(gè)事務(wù)都未提交,或者說行鎖鎖定的記錄之外沒有其他事務(wù)提交的與之有關(guān)的記錄,所以都未用到gap鎖

根據(jù)日志可以發(fā)現(xiàn)update語句會持有排他鎖(共享鎖是in share mode)。

事務(wù)1等待排他鎖,事務(wù)2持有事務(wù)1的排他鎖,并且等待排他鎖。這樣就能死鎖了??為什么事務(wù)1沒有持有事務(wù)2的共享鎖

mysql官方有個(gè)bug帖:https://bugs.mysql.com/bug.php?id=77209

作者的建議:

Donot use index merge when single index is good enough

Try to avoid using index merge in UPDATE to not provoke deadlocks

意思是寫sql的時(shí)候能用一個(gè)索引就盡量不要使用兩個(gè)混合索引去更新,可以先根據(jù)索引查詢出結(jié)果,再執(zhí)行更新來避免死鎖的發(fā)生。


參考文檔:

https://blog.csdn.net/usst_lidawei/article/details/79494177

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容