DeepSeek 幫我解決了一個死鎖問題!
大家好,我是君哥。
最近在生產上遇到一個死鎖問題,Oracle 拋出了 ORA-000060 異常。
業務場景:程序按行讀取一個上游系統送的文件數據(大概有幾萬行),讀取到數據后,每 500 行分配給一個線程去批量更新數據庫(使用主鍵)。表結構類似下面:
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 的深度思考太厲害了。
下面這句話直接給了我思路:
定位到死鎖的原因后,解決方法可能有幾種。如果是應用邏輯的問題,可能需要調整事務的順序,比如讓不同會話以相同的順序訪問表,減少交叉鎖的可能性。
我猜測問題可能就是文件里面存在相同 user_id 的數據,而且文件數據沒有按照 user_id 排序,導致不同線程更新時,出現了鎖等待。類似下面的 2 個線程。
線程一:
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';
我把讀取的文件數據看了一下,確實有這個情況。
不得不說,DeepSeek 確實靠譜,我們看下 DeepSeek 給出的定位死鎖的方法,基本上根據日志、跟蹤文件來判斷。
找到問題原因后,解決方案就很容易了。
- 通知上游系統把文件數據按照 user_id 進行排序;
- 后期優化,相同 user_id 的數據只保留一條日期最新的就行了。
DeepSeek 也給出的詳細的解決死鎖的方法,見下圖:
下面,再看一下 DeepSeek 給出的預防措施和死鎖分析報告示例。
最后,附上 Oracle 官方對 ORA-000060 異常的描述: