Sql-Server
隔離級別問題
在為我的事務選擇正確的隔離級別時,我需要一些幫助。
我的情況如下。我有一個對兩列有唯一約束的表。為了論證的緣故,假設該表稱為 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