Sql-Server

隔離級別問題

  • September 3, 2018

在為我的事務選擇正確的隔離級別時,我需要一些幫助。

我的情況如下。我有一個對兩列有唯一約束的表。為了論證的緣故,假設該表稱為 Animal,列是 Name 和 Owner。所以每個主人只能擁有一隻具有特定名稱的寵物。

我的問題是我在插入過程中收到錯誤,因為它們處於這樣一個階段,以至於我得到了由唯一約束觸發的異常。插入是由儲存過程發生的。在 SP 的開始,我從 Animal 中進行選擇,其中 Owner=x 和 Name=y 以確定動物是否存在,如果存在,則選擇 Id 並繼續,否則插入新動物。proc 的其餘部分使用 Id 在其他表中插入/更新動物詳細資訊。

我知道我可以將隔離級別設置為可序列化,但我很猶豫,因為我知道這會導致死鎖,而且我必須快速執行大量插入,這是一個非常現實的威脅。

歡迎任何建議,謝謝。

最初由Dan Guzman在評論中留下的答案:

我通常使用的方法是顯式事務加上查詢UPDLOCK, HOLDLOCK上的鎖定提示。SELECT這將有助於避免死鎖並避免競爭條件,而無需對整個事務使用可序列化的隔離。

SERIALIZABLE 不會真正有幫助,因為初始選擇將獲得共享(S)範圍鎖。因此,兩個會話都將獲得 S 鎖,然後,您將獲得死鎖,而不是 PK 違規。

除了UPDLOCK之外HOLDLOCK,只有一個會話可以選擇相同的密鑰,無論它是否存在(持有更新密鑰鎖定)或不存在(持有更新密鑰範圍鎖定)。這將序列化對此程式碼路徑中指定鍵的訪問。

這適用於 OP,其實現方式如下:

@Id = SELECT *
 FROM ANIMAL WITH(UPDLOCK, HOLDLOCK)
 WHERE Owner = x AND Name = y
IF(@id <> NULL)
 UPDATE ANIMAL
ELSE
 INSERT ANIMAL

--DO OTHER STUFF

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