在更新记录时锁定记录的最佳方法是什么?

时间:2011-01-04 16:00:10

标签: sql sql-server database

如果我需要SELECT基于存储过程中相对复杂的WHERE子句的表列中的值(恰好是主键列),然后我想要更新记录没有任何其他并发存储过程SELECT相同的记录,是否只是使用事务一样简单?或者我是否还需要将隔离提升到可重复读取?

看起来像这样:

Alter Procedure Blah
As
Declare @targetval int
update table1 set field9 = 1, @targetval = field1 where field1 = (
SELECT TOP 1 field1
FROM table1 t
WHERE
(t.field2 = 'this') AND (t.field3 = 'that') AND (t.field4 = 'yep') AND (t.field9 <> 1))
return

然后我在我的程序中获取了targetval,以便我可以对它进行操作,同时我不必担心其他工作线程抓住相同的targetval。

我在这里谈论SQL 2000,SQL 2005和SQL 2008。

1 个答案:

答案 0 :(得分:2)

ROWLOCK,UPDLOCK添加到子查询中应该这样做。

ALTER PROCEDURE Blah
AS
  DECLARE @targetval INT

  UPDATE table1
  SET    field9 = 1,
         @targetval = field1
  WHERE  field1 = (SELECT TOP 1 field1
                   FROM   table1 t WITH (rowlock, updlock)
                   WHERE  ( t.field2 = 'this' )
                          AND ( t.field3 = 'that' )
                          AND ( t.field4 = 'yep' )
                          AND ( t.field9 <> 1 ))

  RETURN  

更新

此问题的当前接受的答案不使用updlock。我完全不相信这会奏效。据我所知,在这种类型的查询中使用子查询进行测试,SQL Server只会为子查询获取S个锁。但有时子查询会得到优化,因此这种方法似乎可以像查询2一样工作。

测试脚本 - 设置

CREATE TABLE test_table
(
id int identity(1,1) primary key,
col char(40)
)

INSERT INTO test_table
SELECT NEWID() FROM sys.objects

查询1

update test_table
set col=NEWID()
where id=(SELECT top (1) id from test_table )

Plan for id query Trace for id query

查询2

update test_table
set col=NEWID()
where id=(SELECT max(id) from test_table)

Plan for max query Trace for max query