我有一個應用程序需要運行一個任務的單個實例。爲了檢查當前任務的實例是否已經運行,我檢查任務的狀態。如果任務有一個或多個這些狀態的組合,那麼它知道任務已經在運行,現在應該跳過該任務。這些任務可以從多個地方調用,所以我可以有一百個或更多的調用任務在一分鐘內運行。在SQL Server 2008中使用INSERT INTO而無需同時訪問SELECT
我希望某人對我正在使用的SQL執行完整性檢查,並告訴我它是否會正確處理鎖定並僅允許運行一個任務實例。
的SQL:
IF NOT EXISTS(SELECT LogID FROM Log2 T3 WITH (UPDLOCK, HOLDLOCK)
WHERE T3.Param2 = ? AND T3.Action = ? AND T3.LogID NOT IN
(SELECT T2.LogID FROM Log2 T1 WITH (UPDLOCK,HOLDLOCK), Log2 T2 WITH
(UPDLOCK,HOLDLOCK) WHERE T1.Action IN (?,?,?,?,?) AND T2.Action = ?
AND T1.Param3=T2.Param3 AND T1.Param2 = ?))
INSERT INTO Log2 WITH (UPDLOCK) (LogID, Action, EventDateTime) VALUES (?, ?, ?)
的?代表將在運行時插入的值。
上述查詢是否確保在任何時候只有一條記錄被插入,鎖定提示是否正確放置? 目前查詢似乎行爲正常 - 我只是不想讓應用程序生活,並發現查詢不會正確鎖定其他線程,並反過來將允許多個任務運行在相同的時間(因爲多個記錄將被寫出,並且輪詢應用程序將同時記錄2條記錄)。
感謝
我想用['MERGE WITH(HOLDLOCK)'](http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx)是大多數線程安全的方式來實現這一點,因爲在繼續插入之前需要釋放選擇的鎖,所以仍然存在競爭條件的窗口。但是,您應該[謹慎使用合併](https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/),因爲存在邊緣情況,它有點兒越野車。 – GarethD