簡體   English   中英

生成序號遇到死鎖

[英]Generating sequential numbers encountered deadlock

我們需要為交易生成序號。 當並發用戶試圖同時預訂事務時,我們遇到了sqlcode = -911,sqlstate = 40001,sqlerrmc = 2(死鎖)。 當前發生死鎖是因為它正在讀取並更新到同一記錄。 我們如何設計它以防止死鎖?

創建一個包含單個數據行的“種子”表。 該“種子”表行包含“下一個順序”值。

當您希望使用“下一個順序”值插入新的業務數據行時。 執行以下步驟。

1)。 在“種子”表上打開游標以進行UPDATE並獲取當前行。 這使您可以獨家控制種子值。 2)。 您將使用此獲取的行作為“下一個值” ...但是,在這樣做之前3)。 增加獲取的“下一個值”並提交更新。 該提交將關閉光標並釋放帶有新“下一個值”的種子行。

您現在可以自由使用“下一個值”。

有很多方法可以解決此問題,其中一些方法的性能比其他方法差。

如果所有對象都按相同的層次順序鎖定,則可以避免死鎖。 [ https://en.wikipedia.org/wiki/Deadlock#Prevention]

但是,完全防止死鎖的“餐飲哲學家問題”解決方案[ https://en.wikipedia.org/wiki/Dining_philosophers_problem]往往比簡單地回滾事務並重試的效果要差。 您需要測試您的解決方案。

如果您正在尋找數據端解決方案,那么一種老式的(可能性能不佳)的方法是通過建立嚴格的鎖定序列來強制獲取新的事務ID是原子的。

一個快速解決方案(在投入生產之前在負載下進行測試!)可以使用TRANSACTION邊界,並讓控制行充當網守。 這是一個愚蠢的示例,演示了基本技術。 它沒有錯誤檢查,並且收回虛假ID的代碼不在此示例的范圍內:

DECLARE @NewID INTEGER;
BEGIN TRANSACTION;
UPDATE [TABLE] SET [LOCKFLAG] = CURRENT_TIMESTAMP WHERE [ROW_ID] = 0;
SELECT @NewID = MAX([ROW_ID])+1 FROM [TABLE];
INSERT INTO [TABLE] ([ROW_ID]) VALUES (@NewID);
UPDATE [TABLE] SET [LOCKFLAG] = NULL WHERE [ROW_ID] = 0;
COMMIT TRANSACTION;

這樣做的目的是使這種原子的,單線程的,序列化的操作的持續時間非常非常短- 執行安全保留ID並擺脫干擾所需的操作。

通過第一步更新第0行,如果所有ID請求都符合此標准,那么競爭用戶將僅在第一步之后排隊。

保留ID后,請繼續執行所需的操作,然后可以使用新事務更新已創建的行。

您需要處理后面的步驟決定要ROLLBACK ,因為表中現在將有一個幽靈行。 您需要一種方法來回收這些資源; 可以使用各種簡單的解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM