SQL Server遇到錯誤“事務(進程 ID 144)與另一個進程被死鎖在 鎖 | 通信緩衝區 資源上,並且已被選作死鎖犧牲品。請重新運行該事務。”之前也遇到過,上次沒解決,這次再看看。既然出現“死鎖”現象,問題肯定出在更新記錄表上,所以找到被鎖定的表,問題將會解決。找到出問題的存儲過程,發現存在以下update語句
update mytable set name='Daniel'
where id in (select id from mytable where name like '%d%') ;
猜測,問題可能出在批量更新表上。關於鎖定記錄,網上有以下SQL代碼,使用with(updlock)關鍵詞演示記錄被鎖定時的情景。
--打開一個SQL查詢窗口,執行以下SQL語句
begin tran;
select * from mytable with(updlock) where id= 1;
update mytable set name = 'Kate' where id=1;
waitfor delay '00:00:30';
commit tran;
--再打開一個SQL查詢窗口,執行以下SQL語句
update mytable set name = 'Lucy' where id=1;
--再打開一個SQL查詢窗口,執行以下SQL語句
update mytable set name = 'Fiona' where id=1;
執行結果是mytable中id等於1的記錄的name字段值爲'Finona',雖然過程中出現了等待,但最終還是成功執行了記錄。當一條記錄處於鎖定狀態時,其他更新SQL語句需要等待它解鎖,然後方可執行,如果超時,等待執行的SQL將會報“死鎖”錯誤,執行失敗。
本例中,批量更新表mytable時遇到錯誤,猜測待更新的記錄中存在已鎖定記錄,嘗試使用with(nolock)關鍵詞在篩選id時就剔除鎖定狀態的記錄。
經測試,這樣做確實不再出現“死鎖”情況,但也可能存在“漏”更新的記錄,這種“漏”掉的記錄或許會影響數據,也可能不影響。此時,需要從業務上評估其影響性。
綜上所述,解決類似問題有以下兩個途徑:
1、調整業務邏輯,確保sql執行順序合理
2、使用with(nolock)關鍵詞,不過可能存在“漏”更新的風險,想其他辦法處理。