Sql-Server

插入依賴於讀取時處理並發

  • December 14, 2019

$$ Short $$

我有以下情況:使用者A試圖將數據DA插入數據庫。要檢查是否A允許使用者插入DA,我需要執行查詢並進行一些計算。我遇到的問題是,當我進行計算時,另一個使用者 ( B) 也嘗試將數據插入數據庫。現在,假設兩個使用者在插入新數據之前都讀取了計算所需的資訊,那麼他們可能都被清除以進行插入,而來自使用者的數據A將禁止使用者B插入,從而使數據庫處於不一致狀態。

如何在 Azure SQL 數據庫 V12 中解決這種並發問題?

$$ Detailed $$

使用者插入的數據是時間間隔的開始和結束,例如start: 6:00, end: 7:00. 要求是不能有時間間隔重疊。這意味著區間start: 6:00, end: 9:00start: 5:00, end: 6:00不能同時存在。目前我正在做的是檢查是否有任何行與使用者嘗試使用以下查詢插入的新間隔重疊:

SELECT COUNT(*) FROM [Table1] WHERE Start <= attempEnd && End >= attemptStart

現在,問題是多個使用者可能試圖插入一個區間,而這些新的區間可能會相互重疊。但是,在執行上述查詢時,此資訊可能不可用,這會導致插入重疊間隔。

如何在 Azure SQL 數據庫 V12 中解決這種並發問題?

問題是在 A 的事務結束時可能存在一些值 - B 插入的值 - 在 A 第一次檢查時不存在。這被稱為*幻影*

幻像是與搜尋條件匹配但最初看不到的行。

防止幻象的方法是使用 Serializable 隔離級別。這是防止幻象的唯一隔離級別。

還有其他方法可以在不使用該隔離級別的情況下序列化工作負載。一種是使用TABLOCKX獲得整個表的排他鎖。當在顯式事務(BEGIN TRANSACTION)中使用時,這將在表上獲取一個排他鎖並保持它直到事務被送出或回滾。因此,在 A 送出之前,B 將無法插入。但是,表鎖會影響所有工作,包括不會導致間隔重疊的簡單查詢。

更細粒度的方法是使用sp_getapplock。這允許您的程式碼使用自己的語義生成自己的鎖。它充當 MUTEX。當工作負載 A 啟動時,它會獲取此應用鎖。然後它可以繼續執行檢查並插入確信它自己有權這樣做。如果工作負載 B 要同時啟動,它將嘗試獲取 applock 並被阻止,因為該 applock 歸 A 所有。您必須小心,所有可能受到重疊間隔問題影響的工作都必須從獲取此自定義 applock 開始,並且通過釋放它來完成。不受間隔重疊問題影響的寫入,並且所有讀取都可以繼續進行,而無需獲取應用鎖或被它阻止。

引用自:https://dba.stackexchange.com/questions/154664