TSQL:存储过程和ROWLOCK

问题描述:

我有一个多用户系统和存储过程的并发性,如下图所示:TSQL:存储过程和ROWLOCK

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 

它从“新”到“进程内”更新单个记录状态,返回记录的ID。

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

编辑:

01在另一个连接

作为一个反例菲利普德沃思的

注意,使用覆盖索引的 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 

...我得到预期的结果用相同的查询

+0

你的原始答案由链接? – johnny

+0

@Johnny:是的,但我根据你的其他问题添加了一些东西 – gbn

这是不可靠的。因为你给的锁定提示就是这样,锁定提示。另外,根据表索引的方式,结果可能会有很大的不同。

例如:

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 

所以,你可以用它来并发拿起你需要什么,但是这不是在订单并发处理的可靠方法。

我应该使用此存储过程中的事务范围...

在每一个SQL DML语句在事务的上下文中运行,无论你明确打开一个或没有。默认情况下,SQL Server在执行每条语句时将打开一个事务(如果没有打开),执行语句,然后提交事务(如果没有发生错误)或将其回滚。

受@Filip提醒(即仍无法保证项目的选择顺序),它将是安全的,并且每个调用将返回一个不同的行(如果有一个可用且未锁定)。