线程安全的sql事务,如何在事务期间锁定特定的行?

时间:2009-12-17 11:22:40

标签: sql sql-server multithreading sql-server-2008

我有一个这样的程序:

create procedure Checkout
@Foo nvarchar(20),
@cost float
as
begin transaction

declare @Bar nvarchar(20);
select @Bar = Bar from oFoo where Foo = @Foo;

update Foo set gold = gold - @cost where name = @Foo;
update Bar set gold = gold + @cost where name = @Bar;

delete from oFoo where @Foo = Foo;

commit transaction

我需要在此事务中使用oFoo表中的Foo = @Foo锁定行,这样任何人都无法读取/编辑/删除它,有人知道怎么做吗?

我正在使用Microsoft SQL Server 2008

3 个答案:

答案 0 :(得分:10)

如果您不希望任何人更新/删除该行,我会使用SELECT语句中的UPDLOCK。这表示您将很快更新同一行,例如

select @Bar = Bar from oFoo WITH (UPDLOCK) where Foo = @Foo;

现在,如果你想要没有人能够读取该值的情况,我会使用ROWLOCK(+ HOLDLOCK XLOCK使其独占并保持到事务结束)。

您可以执行TABLOCK(X),但这会锁定整个表以供该一个事务独占访问。即使某人出现并希望在另一行上执行您的程序(例如,使用另一个@Foo值),它们也会被锁定,直到上一个事务完成。

注意:您可以使用此脚本模拟不同的方案:

CREATE TABLE ##temp (a int, b int)
INSERT INTO ##temp VALUES (0, 0)

客户#1

BEGIN TRAN
SELECT * FROM ##temp WITH (HOLDLOCK XLOCK ROWLOCK) WHERE a = 0
waitfor delay '0:00:05'
update ##temp set a = 1 where a = 0
select * from ##temp
commit tran

客户#2:

begin tran
select * from ##temp where a = 0 or a = 1
commit tran

答案 1 :(得分:1)

请参阅:http://www.mssqlcity.com/Articles/Adm/SQL70Locks.htm

并且:http://msdn.microsoft.com/en-us/library/ms173763.aspx

请特别注意MSDN页面:

READ COMMITTED

Specifies that statements cannot read data that has been modified but not committed
by other transactions. This prevents dirty reads. Data can be changed by other
transactions between individual statements within the current transaction, resulting
in nonrepeatable reads or phantom data. This option is the SQL Server default.

答案 2 :(得分:1)

(基于SQL Server)

我认为,当谈到Table提示时,您需要进行实验(TABLOCK,TABLOCKX),并查看最适合您的方法。另请注意,查询优化器可能会忽略提示。如果查询优化器未选择表并在后续查询计划中使用表,则将忽略表级提示。

关于这个主题的另一篇有用的文章,虽然有点旧,因为它基于SQL Server 2000是SQL Server 2000 Table Locking Hints