Sql-Server
SQL 死鎖 - 同時呼叫的相同儲存過程
我正在使用一個相對複雜的系統,其中靜態表根據需要從多個數據源更新,因為動態載入數據需要 4-5 秒,我們更喜歡快速向使用者顯示結果。
過程:
- 使用者或應用程序打開特定訂單
- 呼叫儲存過程來檢索數據(我們稱之為 dbo.Get_Data)
- dbo.Get_Data 檢查事件日誌以查看自上次查找數據以來是否有任何更改
- 如果它發現一個新事件,它會執行昂貴的查詢來更新數據
- 返回數據
IF ( SELECT [LastStaticUpdateEvent] < [LastSaveEvent] FROM [dbo].[Events] WHERE [OrderNumber] = @OrderNumber ) BEGIN -- Update Static table UPDATE [Static] SET [Static].[A] = [App].[A] ,[Static].[B] = [App].[B] FROM [dbo].[AppData] AS [App] -- View with many joins (4-5 secs) INNER JOIN [dbo].[StaticResuts] AS [Static] ON [Static].[OrderNumber] = [App].[OrderNumber] WHERE [App].[OrderNumber] = @OrderNumber -- Update Event Log UPDATE [dbo].[Events] SET [LastStaticUpdateVent] = SYSDATETIME() WHERE [OrderNumber] = @OrderNumber END SELECT * FROM [dbo].[StaticResults]
問題是可以同時請求這些數據。如果使用者 A 和使用者 B 在第一次 UPDATE 完成之前都呼叫了 dbo.Get_Data,則會發生死鎖。
是否有一個好的方法或模式讓第二次呼叫等到第一次呼叫完成後再繼續查找?
是否有一個好的方法或模式讓第二次呼叫等到第一次呼叫完成後再繼續查找?
擁有一次只能由一個會話執行的程式碼塊的最簡單方法是使用Application Lock。您可以使用 SQL Server 的鎖定引擎,但不是鎖定特定的行、頁或表,而是創建具有自定義名稱的鎖。例如
begin transaction; --begin exclusive section exec sp_getapplock @Resource = 'Get_Data Exclusive Lock', @LockMode = 'Exclusive'; --do stuff in only one session --end exclusive section exec sp_releaseapplock @Resource = 'Get_Data Exclusive Lock'; commit transaction;