2016-11-22 75 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子句或一个唯一的约束来防止多个记录(从而任务)。

如果两个源尝试在完全相同的毫秒内启动进程,则只有其中一个会成功,并根据查询的返回值知道是启动任务还是跳过它。

这样你就不用担心锁定了。