如何同时对表中的行进行操作

时间:2015-05-07 12:20:38

标签: sql sql-server sql-server-2008

假设我有一个名为Task的表:

| ID | TASK    | Other columns... |
|  1 | ...     | ...              |
|  2 | ...     | ...              |
|  3 | ...     | ...              |

我有一个存储过程:

  • 从任务表
  • 中选择所有可用行
  • 使用此数据执行某些操作,例如更新其他表格
  • 从任务
  • 中删除这些行

此存储过程将由许多客户端应用程序同时调用。如何让存储过程在互斥行上工作? E.g。

  • 任务1和2位于任务表
  • 调用存储过程并选择任务1和2并开始处理它们
  • 添加了任务3(上面的存储过程仍在运行)
  • 同时再次调用存储过程(先前的存储过程尚未完成)。这次存储过程应该只选择任务3。
  • 当任一存储的proecdure结束时,它应该从任务表
  • 中删除它所处理的任务

1 个答案:

答案 0 :(得分:0)

我宁愿建议采用乐观的并发控制方法。这是通过在sql server中使用timestamp列实现的。每次更新记录时,时间戳值都会自动增加。

每当您触发选择查询时,您都必须选择主键列和时间戳列。每当您更新此记录时,您的查询应该如下所示

UPDATE t SET Name = 'XYZ' from Employee t WHERE t.PrimaryKeyColumn = @Col1 
AND t.TimeStamp = @Timestamp

IF @@RowCount = 0
BEGIN
RAISEERROR('Record has been updated by another user',16, 1)
END

修改

满足您的问题要求

我可以考虑创建一个全局临时表,其中包含一个名为SPID(connectionID)的附加列,其默认值为NULL

select *, NULL AS spId into ##TaskList

这里的关键是这个全局临时表将可用,直到创建它的进程范围。因此,您可以使用一个永久表来执行此任务,或者让临时表的创建者保持活动状态。

由于每个存储过程都将在不同的数据库连接下运行,因此它们都将具有唯一的SPID。

任何处理T1,T3的进程必须在T1,T3上开始进程之前将其SPID更新为此全局临时表。

类似的剩余proc将查询## TaskList以锁定他们想要处理的SPID = NULL的任务。

SELECT * FROM ##TaskList where SPID IS NULL
UPDATE SPID = @@SPID FROM ##TaskList where Task IN (T2, T4)

通过这种方法,所有任务都将与存储过程互斥。