sql-server – 用于FIFO队列的SQL Threadsafe UPDATE TOP 1
我准备了一张发票表,然后准备打印.
[STATUS]列是草稿,打印,打印 我需要获取要打印的第一个(FIFO)记录的ID,并更改记录状态.该操作必须是线程安全的,以便另一个进程不会选择相同的InvoiceID 我可以这样做(对我来说看起来很原始,但也许不是……): 1: WITH CTE AS ( SELECT TOP(1) [InvoiceID],[Status] FROM INVOICES WHERE [Status] = 'Print' ORDER BY [PrintRequestedDate],[InvoiceID] ) UPDATE CTE SET [Status] = 'Printing',@InvoiceID = [InvoiceID] …使用@InvoiceID执行操作… UPDATE INVOICES SET [Status] = 'Printed' WHERE [InvoiceID] = @InvoiceID 或者我必须使用它(对于第一个声明) 2: UPDATE INVOICES SET [Status] = 'Printing',@InvoiceID = [InvoiceID] WHERE [InvoiceID] = ( SELECT TOP 1 [InvoiceID] FROM INVOICES WITH (UPDLOCK) WHERE [Status] = 'Print' ORDER BY [PrintRequestedDate],[InvoiceID] ) …使用@InvoiceID执行操作……等 (在处理结束之前,即状态最终变为“已打印”时,我无法将状态从更改状态保持为“打印”. 编辑: 如果重要,则DB为READ_COMMITTED_SNAPSHOT 我可以将UPDATE STATUS的交易保持为“打印”并获取ID.但我不能继续保持交易一直打开,将状态更改为“已打印”.这是一个SSRS报告,它对SQL进行了几次不同的查询以获取发票的各个部分,并且可能会崩溃/无论如何,使事务保持打开状态. @Gordon Linoff“如果你想要一个队列”FIFO序列并不重要,我只想首先要求打印的发票……“或多或少”(不要有任何不必要的复杂性……) @Martin Smith“看起来像通常的表作为队列要求” – 是的,正是如此,感谢非常有用的链接. 解: 我采用的解决方案来自评论: @ lad2025指向我SQL Server Process Queue Race Condition使用WITH(ROWLOCK,READPAST,UPDLOCK)和@MartinSmith解释了隔离问题是什么,并指出我在Using tables as Queues – 它正在谈论我正在尝试做什么. 我没有理解为什么UPDATE TOP 1是安全的,UPDATE MyTable SET xxx = yyy WHERE MyColumn =(SELECT TOP 1 SomeColumn FROM SomeTable ORDER BY AnotherColumn)(没有隔离提示)不是,我应该教育自己,但我’我很乐意将隔离提示放在我的代码中并继续使用其他东西:) 谢谢你的帮助. 解决方法我担心的是重复[InvoiceID]多个打印请求相同[InvoiceID] 在第一次更新时,ONE行设置[Status] =’Printing’ 在第二次更新时,所有[InvoiceID]行都设置为[Status] =’Printed’ 也许这就是你想要的 另一个进程可以在设置[Status] =’Print’之前选择相同的[InvoiceID] 所以有些重复会打印,有些则不打印 我带着关于使用更新锁的评论 这是不确定的,但你可以采取top(1)并跳过订单.您将倾向于获得最新的行但不保证.如果你清除了队列,那么你就可以了. 这表明你可以失去’draft’= 1 declare @invID int; declare @T table (iden int identity primary key,invID int,status tinyint); insert into @T values (1,2),(5,1),(3,(4,(2,(1,2); declare @iden int; select * from @t order by iden; declare @rowcount int = 1; while (@ROWCOUNT > 0) begin update top (1) t set t.status = 3,@invID = t.invID,@iden = t.iden from @t t where t.status = '2'; set @rowcount = @@ROWCOUNT; if(@rowcount > 0) begin select @invID,@iden; -- do stuff update t set t.status = 4 from @t t where t.invID = @invID; -- t.iden = @iden; select * from @T order by iden; end end (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |