【问题标题】:Row locks - manually using them行锁 - 手动使用它们
【发布时间】:2015-11-26 23:29:37
【问题描述】:

我基本上有一个应用程序,它有 5 个线程,每个线程都从一个表中读取。该查询是一个简单的 SELECT TOP 1 * from table,但我想强制执行锁定,以便下一个线程将从表中选择下一条记录,而不是锁定的记录。当应用程序完成它的任务时,它将更新锁定的记录并释放锁定并再次重复该过程。这可能吗?

【问题讨论】:

  • 我假设这是 SQL Server - 对吗?

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


【解决方案1】:

我推荐的方法是在记录中设置一个字段,指示记录是否正在处理。然后实现一个“从队列中读取下一个”sproc,它执行以下操作,以确保没有 2 个进程获取相同的记录:

BEGIN TRANSACTION

-- Find the next available record that's not already being processed.
-- The combination of UPDLOCK and READPAST hints makes sure 2 processes don't 
-- grab the same record, and that processes don't block each other.
SELECT TOP 1 @ID = ID
FROM YourTable WITH (UPDLOCK, READPAST)
WHERE BeingProcessed = 0

-- If we've found a record, set it's status to "being processed"
IF (@ID IS NOT NULL)
    UPDATE YourTable SET BeingProcessed = 1 WHERE ID = @ID

COMMIT TRANSACTION

-- Finally return the record we've picked up
IF (@ID IS NOT NULL)
    SELECT * FROM YourTable WHERE ID = @ID

有关这些表格提示的更多信息,请参阅MSDN

【讨论】:

  • 感谢您的快速回复。我必须立即执行更新声明吗?如果我在 SELECT 之后提交事务,那会保留 LOCK 吗?
  • 不,锁不会留在原地。
  • 是的,这是 SQL Server,准确地说是 2008。所以,我需要在应用程序中启动一个事务,选择记录,在应用程序中进行必要的处理,更新记录并提交事务以保持行锁定?
  • 如果您不想拥有“BeginProcessed”标志,那么可以。上面的这种方法是进行这种队列处理的推荐方法。或者,您可以使用 MSMQ 之类的东西
  • 您是否还想使用 ROWLOCK 以便其他进程在同一页面上获取行?
【解决方案2】:

Sql Server 中的Service Broker Queues 是专门为解决这种情况而设计的。

必须锁定表和行似乎是实现此功能的一种倒退方式。

【讨论】:

  • 论点很好,但是 1) 声称它们难以使用是愚蠢的,它们根本不是。这可能更容易,但肯定不难。 2)我同意,有一个灵活的结构会很好。 3)缺乏维护只会在例外情况下成为真正的问题〜3,000 + msg / s。在这种情况下,我认为这更多的是设计问题,而不是技术的失败。此外,上述建议的解决方案不会规避碎片问题,而是更容易解决。
  • 本文作者是服务代理开发人员之一,因此如果他们建议使用表作为队列而不是服务代理,我倾向于将其视为表面价值。
【解决方案3】:

有关此技术的更多详细文章“使用 READPAST 和 UPDLOCK 在 SQL Server 中处理数据队列”

https://www.mssqltips.com/sqlservertip/1257/processing-data-queues-in-sql-server-with-readpast-and-updlock/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2016-05-13
    相关资源
    最近更新 更多