tsql:存储过程和行锁

时间:2011-08-08 08:22:43

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

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

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

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

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

3 个答案:

答案 0 :(得分:2)

  

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

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

受@Filip警告提及(仍无法保证选择项目的顺序),它将是安全的,并且每次调用将返回不同的行,如果有可用且未锁定。 / p>

答案 1 :(得分:2)

编辑:

作为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

...我在同一个查询的另一个连接中获得了预期的结果

答案 2 :(得分:1)

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

例如:

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

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