DeepSeek 幫我解決了一個(gè)死鎖問題!
大家好,我是君哥。
最近在生產(chǎn)上遇到一個(gè)死鎖問題,Oracle 拋出了 ORA-000060 異常。
業(yè)務(wù)場(chǎng)景:程序按行讀取一個(gè)上游系統(tǒng)送的文件數(shù)據(jù)(大概有幾萬行),讀取到數(shù)據(jù)后,每 500 行分配給一個(gè)線程去批量更新數(shù)據(jù)庫(使用主鍵)。表結(jié)構(gòu)類似下面:
user_id(PK) | user_name | age | sex |
00001 | tom | 6 | man |
00002 | jimi | 11 | woman |
給出一段批量更新的代碼:
<update id="updateUser" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update tb_user set user_name=#{item.userName} age = #{item.age} where user_id= #{item.userId}
</foreach>
</update>
遇到問題后,我們想先問一下 DeepSeek,看它能不能幫忙解決。不得不說,DeepSeek 的深度思考太厲害了。
下面這句話直接給了我思路:
定位到死鎖的原因后,解決方法可能有幾種。如果是應(yīng)用邏輯的問題,可能需要調(diào)整事務(wù)的順序,比如讓不同會(huì)話以相同的順序訪問表,減少交叉鎖的可能性。
我猜測(cè)問題可能就是文件里面存在相同 user_id 的數(shù)據(jù),而且文件數(shù)據(jù)沒有按照 user_id 排序,導(dǎo)致不同線程更新時(shí),出現(xiàn)了鎖等待。類似下面的 2 個(gè)線程。
線程一:
update tb_user set user_name=#{item.userName} age = #{item.age} where user_id = '00001';
update tb_user set user_name=#{item.userName} age = #{item.age} where user_id = '00002';
線程二:
update tb_user set user_name=#{item.userName} age = #{item.age} where user_id = '00002';
update tb_user set user_name=#{item.userName} age = #{item.age} where user_id = '00001';
我把讀取的文件數(shù)據(jù)看了一下,確實(shí)有這個(gè)情況。
不得不說,DeepSeek 確實(shí)靠譜,我們看下 DeepSeek 給出的定位死鎖的方法,基本上根據(jù)日志、跟蹤文件來判斷。
找到問題原因后,解決方案就很容易了。
- 通知上游系統(tǒng)把文件數(shù)據(jù)按照 user_id 進(jìn)行排序;
- 后期優(yōu)化,相同 user_id 的數(shù)據(jù)只保留一條日期最新的就行了。
DeepSeek 也給出的詳細(xì)的解決死鎖的方法,見下圖:
下面,再看一下 DeepSeek 給出的預(yù)防措施和死鎖分析報(bào)告示例。
最后,附上 Oracle 官方對(duì) ORA-000060 異常的描述: