Sql 如何并发操作表中的行

Sql 如何并发操作表中的行,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,假设我有一个名为Task的表: | ID | TASK | Other columns... | | 1 | ... | ... | | 2 | ... | ... | | 3 | ... | ... | 我有一个存储过程: 从任务表中选择所有可用行 使用此数据执行某些工作,例如更新其他表 从任务中删除这些行 此存储过程将由多个客户端应用程序同时调用。如何使存储过程在互斥行上工作?

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

| ID | TASK    | Other columns... |
|  1 | ...     | ...              |
|  2 | ...     | ...              |
|  3 | ...     | ...              |
我有一个存储过程:

从任务表中选择所有可用行 使用此数据执行某些工作,例如更新其他表 从任务中删除这些行 此存储过程将由多个客户端应用程序同时调用。如何使存储过程在互斥行上工作?例如

任务1和2在任务表中 调用存储过程并选择任务1和任务2,然后开始处理它们 任务3已添加。上面的存储过程仍在运行 再次并发调用存储过程之前的存储过程尚未完成。这次存储过程应该只选择Task3。 当任一存储过程结束时,它应该从任务表中删除已处理的任务
我宁愿建议使用乐观并发控制方法。这是通过在SQLServer中使用时间戳列实现的。每次更新记录时,时间戳值都会自动递增

无论何时启动select查询,都必须选择主键列和时间戳列。无论何时更新此记录,您的查询应该如下所示

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
编辑:

按照你的问题要求

我可以考虑创建一个全局临时表,其中包含名为SPIDconnectionID的附加列,默认值为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)

通过这种方法,所有任务对存储过程都是互斥的。

Read now我有一个可行的解决方案,但它会从任务表中选择每一行。所以在上面描述的场景中。第一个s-proc在任务1和2上运行;秒s-proc在任务1、2和3上运行假定第一个s-proc在第二个s-proc启动时未删除任务1和2如果运行s-proc时表中有数千个任务,我希望它一次对所有行进行操作,一次不能调用一个队列-我假设队列就是这样?为什么要从多个客户端调用它?只要让它在所有行上运行,SQL Server就会使用任何可用的处理器。听起来你把事情复杂化了。继续对符合条件的任务运行它,直到什么都没有了。我将如何调用它?例如,客户端A插入许多任务,然后调用存储过程。然后6小时后,客户端B插入了更多任务,需要再次调用存储过程。我同意,一般来说,乐观并发更好,对于让记录处理“任务”的特定情况,它不起作用,因为所有并发事务都选择相同的记录来处理。结果是,除了第一个获胜的处理器外,所有处理器都存在冲突。对于乐观并发工作来说,冲突的概率必须很低,当更新的记录基本上是随机的时,它工作得很好,但当更新的记录是确定性的时,它就失败了,即每个人都选择“下一个任务”。