我有一个用作队列的 SQL 表。
基本上,我有一个多线程进程,它读取未处理的项目并相应地对这些项目采取行动并设置一个已处理的位。假设两个进程非常接近,[Process 1] 读取队列中的下一项。
如果由于某种原因 [Process 1] 还没有时间设置已处理的位,我如何防止 [Process 2] 读取刚刚读取的相同项目 [Process 1]?
注意:还有另一个将项目添加到队列的完整过程。我不想限制/阻止该过程添加项目。
我有一个用作队列的 SQL 表。
基本上,我有一个多线程进程,它读取未处理的项目并相应地对这些项目采取行动并设置一个已处理的位。假设两个进程非常接近,[Process 1] 读取队列中的下一项。
如果由于某种原因 [Process 1] 还没有时间设置已处理的位,我如何防止 [Process 2] 读取刚刚读取的相同项目 [Process 1]?
注意:还有另一个将项目添加到队列的完整过程。我不想限制/阻止该过程添加项目。
弄清楚了:
BEGIN TRAN
SELECT TOP * FROM TABLE WITH (XLOCK, ROWLOCK, READPAST)
UPDATE TABLE SET Processed = 1
END TRAN
XLOCK和ROWLOCK锁定了我刚刚读取的行。READPAST将读取当前锁定的行。
因此,[过程 1] 读取第一行并将其锁定。[过程 2] 将自动读取下一个未锁定(未读)的行。
你有几个选择。在表中包含一status
列怎么样?例如,将其设置1
为意味着正在处理记录。当您查询要处理的记录时,只需忽略状态为 1 的任何内容。
你说有一个已处理的位。您可以在每次读取新项目时进行比较,以确保其处理位未设置为 1。
如果Process1需要很长时间才能运行,则: 1.在Process1开始时将Processed位设置为 1 或 2. 按照 Ash 的上述说明创建一个新位并将该位设置为 1。
向表中添加一个新列,我们将其称为 processesId
创建执行以下操作的存储过程:
生成指南。将 processesId 设置为等于此 guid 值,其中 processedid 为空。返回表中处理的id 等于您生成的guid 的所有行。
declare @processedId uniqueidentifier = NEWID()
update table set processedid=@procesedId where processedid is null
select * from table where processedid = @processedid
这里的关键是先进行更新,然后返回在此事务中更新的行。