2017-08-03 77 views
0

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

+2

請提供更多信息,究竟是什麼造成死鎖,調用代碼是什麼,db設計是什麼?目前沒有什麼可繼續。 – GurV

+1

在這種情況下通常要做的事情就是趕上例外情況並再次嘗試。另一種方法是在數據庫表中創建事務並讓數據庫本身爲其生成主鍵。 –

+0

您可以使用同步關鍵字來防止死鎖。同步塊確保只有在當前線程成功輸入對象的監視器後纔會調用作爲對象成員的方法。一旦一個線程在一個實例上輸入任何同步方法,其他線程就不能輸入任何其他同步方法。 – Tehmina

回答

0

圍繞這個問題有很多解決方法,其中一些問題比其他問題少。

如果所有對象都被鎖定在相同的層次序列中,則可以防止死鎖。 [https://en.wikipedia.org/wiki/Deadlock#Prevention]

然而,完全防止死鎖的餐飲哲學家問題的解決方案往往不如簡單地回滾事務和重試。你需要測試你的解決方案。

如果您正在尋找數據端解決方案,那麼老式(可能性能不足)方法就是通過建立嚴格的鎖定序列來強制要求獲取新的事務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; 

我們的想法是,使這個原子,單線程,系列化操作非常,在持續時間很短的 - - 做只有需要什麼來安全地保留身份證並避開。

通過第一步更新第0行,如果所有ID請求都符合此標準,則競爭用戶將在第一步之後簡單排隊。

一旦您保留您的ID,請關閉並執行您喜歡的操作,並且您可以使用新的事務來更新您創建的行。

您需要覆蓋後面的步驟決定爲ROLLBACK的情況,因爲表中現在會有一個虛影行。你會想要一個方法來回收這些;可以使用各種簡單的解決方案。

1

創建一個包含單個數據行的「種子」表。 此「種子」表格行保存「下一個順序」值。

當您希望使用「Next Sequential」值插入新的業務數據行時。執行以下步驟。

1)。在「seed」表上打開UPDATE遊標並獲取當前行。這使您可以獨佔控制種子值。 2)。你將使用這個提取的行作爲「下一個值」...但是在這之前,你可以使用3)。增加提取的「下一個值」並提交更新。這個提交關閉你的光標,並用新的「下一個值」釋放種子行。

你現在可以自由使用你的「下一個價值」。

+1

您可能遇到的其他名稱描述了這種方法:高水位標記,序列ID表和主交易表。 ++ Hector可以更有效地使用專用的表格。不確定CURSOR是否比簡單的TRANSACTION邊界更有效率,但是您可以同時使用這兩者來查看您的環境中的工作情況。 –

+0

我在許多企業生產系統中使用Cursor進行更新。這種方法以有序的方式排隊請求「下一個值」,我已經看到它在主機z/OS DB2上支持非常高的TPS 100 - > 1000。 – Hector

+0

非常好。我想我會加入我的個人「額外時間」來做清單,試圖在兩種技術之間進行性能比較。因爲,知道很好,玩得很開心。 :-) –