如何實現以下事務鎖定?T-SQL選擇並更新鎖定 - 事務或表提示
大簡化 - 我有一個包含狀態(創建,啓動,完成)的「任務」表。我想創建存儲過程GetNext
以獲得尚未開始的最高1任務(具有Created
狀態)。
在這個過程中,我想將任務標記爲Started
。很明顯,我想避免兩個進程調用此過程並獲得相同任務時的情況。
該過程不會被頻繁調用,因此性能不是問題,保持數據不被破壞是一個問題。
所以我希望做這樣的事情:
UPDATE tblTasks
SET Status = 'Started'
WHERE TaskId = (SELECT TOP 1 TaskId
FROM tblTasks
WHERE Status = 'Created')
我也想接受,我剛剛更新,以便而不是什麼高於我的任務需要這樣的東西:
DECLARE @TaskId AS INT = (SELECT TOP 1 TaskId FROM tblTasks WHERE Status = 'Created')
UPDATE tblTasks
SET Status = 'Started'
WHERE TaskId = @TaskId
[... - Do something with @TaskId - not relevant]
OR
DECLARE @TaskIds AS TABLE(Id INT)
UPDATE tblTasks
SET Status = 'Started'
OUTPUT INSERTED.Id INTO @TaskIdS
WHERE TaskId = @TaskId
[... - Do something with @TaskIds - not relevant]
因此,假設我需要選擇+更新來實現我所需要的 - 我如何確保t即使第一次操作(選擇),其他進程也不會執行直到現有進程完成?
據我瞭解,即使可串行化隔離級別的事務在這裏是不夠的,因爲其他進程可以讀取數據,然後等到我完成(因爲它的更新被鎖持有)並更新剛剛更新的數據。
我覺得表提示XLOCK
或HOLDLOCK
可能有幫助,但我不是專家和MS文檔嚇我:
注意
因爲SQL Server查詢優化器通常選擇一個最佳的執行計劃查詢,我們建議提示僅作爲經驗豐富的開發人員和數據庫管理員的最後手段使用。
(從https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table)
那麼,如何確保兩個進程將無法更新一個項目,也是我該如何確保,如果一個進程正在運行的其它將等待後完成其工作第一次結束而不是失敗?
備註 - 使用'top 1'而不指定'order by'子句並不意味着「獲取第一條記錄」,它僅僅意味着「獲取一條記錄」。這是因爲數據庫表本質上是無序的,所以如果沒有'order by'子句,關係數據庫就不能保證返回記錄的順序。 –
您應該閱讀[這篇Dan Guzman的文章](http:// weblogs。sqlteam.com/dang/archive/2007/10/28/Conditional-INSERTUPDATE-Race-Condition.aspx) –