1

我有大約20個相互使用的存儲過程,形成一個樹狀的依賴關係鏈。sp_getapplock用於同步對內存表的併發訪問

但是,存儲過程使用內存表進行緩存,可以從多個不同的客戶端同時調用。

爲防止針對內存表的併發更新/刪除嘗試,我使用了sp_getapplock和SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT ON;

我正在使用每個存儲過程獨有的存儲過程參數的散列,但對具有相同參數的同一存儲過程的多個併發調用應生成相同的散列。這就是對同一個存儲過程的併發調用的哈希值的相等性,這些參數的相同參數爲我提供了一個有用的資源名稱來獲取我們的applock。

下面是一個例子:

BEGIN TRANSACTION 

EXEC @LOCK_STATUS = sp_getapplock @Resource= [SOME_HASH_OF_PARAMETERS_TO_THE_SP], @LockMode = 'Exclusive'; 

...some stored proc code... 

IF FAILURE 
BEGIN 
    ROLLBACK; 
    THROW [SOME_ERROR_NUMBER] 
END 

...some stored proc code... 

COMMIT TRANSACTION 

儘管這應該阻止任何併發更新或刪除一個的AppLock包裝的一切,我仍然得到錯誤41302:

當前事務嘗試更新記錄自該交易開始以來已更新爲 。交易被中止。 在批處理結束時檢測到不可提交的事務。回滾事務 。

我是否正確使用sp_getapplock?這似乎是我建議的方法應該起作用。

回答

5

第二次開始您的事務時使用內存優化表,您可以獲得基於事務開始時間的「快照」,以實現樂觀的併發解析。不幸的是,在拍攝快照之後,您的鎖定仍然存在,因此仍然完全有可能存在樂觀的併發解決失敗。

考慮需要同一鎖定的兩個事務立即開始的情況。他們都在「獲得鎖定或修改任何行之前」同時開始他們的交易。他們的快照看起來完全一樣,因爲尚未修改數據。接下來,一個事務獲取鎖並繼續進行更改,而另一個被阻止。此事務提交正常,因爲它是第一個,因此它引用的快照仍然與內存中的數據匹配。另一個事務現在獲得鎖,但它的快照是無效的(但它現在還不知道)。它繼續執行,並在最後意識到其快照是無效的,因此它會引發錯誤。事實上,事務甚至不需要同時開始,第二個事務只需在第一次提交之前啓動。

您需要強制執行應用程序級別的鎖定,或者通過在會話級別使用sp_getapplock。

希望這有助於。

+0

這正是答案。它不能說得比你的回答和例子更清楚。實際上我幾天前終於明白了這一點,所以我知道你的答案是完全正確的。感謝您的迴應。 –

+0

會話鎖定有助於(https://msdn.microsoft.com/en-us/library/ms189823.aspx,LockOwner =「Session」),特別是在快照模式下。首先獲取會話鎖並開始一個事務。這似乎是唯一正確的方法。 – Martijn