【问题标题】:tsql: stored procedure and rowlocktsql:存储过程和行锁
【发布时间】:2026-01-11 08:30:02
【问题描述】:

我在多用户系统中有并发,存储过程如下图:

CREATE PROCEDURE dbo.GetWorkitemID
AS
DECLARE @workitem int;

UPDATE workqueue
SET status = 'InProcess', @workitem = workitemid
WHERE workitemid = (SELECT TOP 1 workitemid
FROM workqueue WITH (ROWLOCK,UPDLOCK,READPAST)
WHERE status = 'New' ORDER BY workitemid)

SELECT @workitem

GO

它将单个记录状态从“New”更新为“InProcess”并返回记录的 ID。

问题如下:我应该在事务范围内使用这个存储过程来启用ROWLOCK、UPDLOCK等吗?是必需的吗?第二个:它真的是线程安全的并保证唯一性吗?

【问题讨论】:

    标签: sql-server tsql sql-server-2008 stored-procedures


    【解决方案1】:

    编辑:

    作为 Filip De Vos 的反例

    注意使用覆盖索引 UPDLOCK不是XLOCK 同一个查询

    DROP table locktest
    create table locktest (id int, workitem int, status varchar(50))
    insert into locktest (id, workitem) values (1, 1), (2,2), (3,3)
    create index ix_test2 on locktest(workitem) INCLUDE (id, status)
    
    --When I run this on one connection
    begin tran 
    select top (1) id, status 
    from locktest with (rowlock, updlock, readpast) 
    ORDER BY workitem
    

    ...我在使用相同查询的另一个连接中得到预期结果

    【讨论】:

    • 你原来的答案是链接吗?
    • @Johnny:是的,但我根据你的其他问题添加了一些东西
    【解决方案2】:

    我应该在事务范围内使用这个存储过程吗...

    SQL 中的每个 DML 语句都在事务的上下文中运行,无论您是否显式打开一个。默认情况下,在执行每条语句时,SQL Server 会打开一个未打开的事务,执行该语句,然后提交该事务(如果没有发生错误)或回滚。

    除了@Filip 提到的警告(仍然不能保证选择项目的顺序),它将是安全的,并且每次调用将返回不同的行,如果一个可用且未锁定。

    【讨论】:

      【解决方案3】:

      这不可靠。因为您提供的锁定提示就是锁定提示。此外,根据表的索引方式,结果可能会有很大差异。

      例如:

      create table test (id int, workitem int, status varchar(50))
      insert into test (id, workitem) values (1, 1), (2,2), (3,3)
      create index ix_test on test(workitem)
      

      当我在一个连接上运行它时

      begin tran 
      select * from test with (rowlock, xlock, holdlock) where workitem = 1
      

      我在第二个连接上运行它:

      select top (1) * from test with (rowlock, readpast) order by workitem
      

      这会返回:

      workitem
      --------
      3 
      

      如果我这样做也一样:

      update top (1) test with (rowlock, readpast)
      set status = 'Proc' 
      output inserted.workitem
      

      因此,您可以使用它来并发获取所需的内容,但这不是进行有序并发处理的可靠方法。

      【讨论】:

        最近更新 更多