2011-08-08 168 views
3

我有一個多用戶系統和存儲過程的併發性,如下圖所示: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等嗎?需要嗎?第二:它是否真的線程安全並保證唯一性?

回答

2

編輯:

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

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 

所以,你可以用它來併發拿起你需要什麼,但是這不是在訂單併發處理的可靠方法。

2

我應該使用此存儲過程中的事務範圍...

在每一個SQL DML語句在事務的上下文中運行,無論你明確打開一個或沒有。默認情況下,SQL Server在執行每條語句時將打開一個事務(如果沒有打開),執行語句,然後提交事務(如果沒有發生錯誤)或將其回滾。

受@Filip提醒(即仍無法保證項目的選擇順序),它將是安全的,並且每個調用將返回一個不同的行(如果有一個可用且未鎖定)。