2016-11-22 24 views
0

我有一個應用程序需要運行一個任務的單個實例。爲了檢查當前任務的實例是否已經運行,我檢查任務的狀態。如果任務有一個或多個這些狀態的組合,那麼它知道任務已經在運行,現在應該跳過該任務。這些任務可以從多個地方調用,所以我可以有一百個或更多的調用任務在一分鐘內運行。在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條記錄)。

感謝

+0

我想用['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

回答

0

我發現這樣做,這是使用插入或更新而不最初選擇的最佳方式。你可以有一個where子句或一個唯一的約束來防止多個記錄(從而任務)。

如果兩個源嘗試在完全相同的毫秒內啓動進程,則只有其中一個會成功,並根據查詢的返回值知道是啓動任務還是跳過它。

這樣你就不用擔心鎖定了。