【问题标题】:How to lock a row in a table before updating it如何在更新之前锁定表中的行
【发布时间】:2014-11-20 13:56:15
【问题描述】:

要在 SQL Server 2012 中为我的更新任务实现多线程,我需要让不同的线程从表(帐户)中选择一行并将该行标记为使用存储过程中的更新处理。

类似这样的:

create procedure ChooseNextAccountToProcess (@Account_ID Int Output)

    select top 1 @Account_ID = Account_ID 
    from Accounts 
    order by LastProcessDate Desc

    update Accounts 
    set LastProcessDate = getdate() 
    where Account_ID = @Account_ID 
go

这种方法的问题是两个线程可能同时调用这个存储过程并处理同一个帐户。我的目标是从帐户表中选择一个帐户并在更新有机会更新它之前专门锁定它。

我尝试了SELECT .... WITH (UPDLOCK)WITH Exclusive lock,但是当我选择该行时,这些都不能真正在该行上设置排他锁。

有什么建议吗?

【问题讨论】:

  • 为什么不直接更新呢?这将立即锁定该行。
  • 如果您确实需要捕获 Account_ID,您可以使用 OUTPUT 来完成。从您发布的内容来看,这确实应该是一个单行程序。

标签: sql sql-server multithreading


【解决方案1】:

可以使用update top (n) ...,但不能在语句中直接指定order by。所以,需要一个小技巧:

declare @t table (
    Id int primary key,
    LastProcessDate date not null
);

insert into @t (Id, LastProcessDate)
values
    (1, getdate() - 10),
    (2, getdate() - 7),
    (3, getdate() - 1),
    (4, getdate() - 4);


-- Your stored procedure code starts from here
declare @res table (Id int primary key);

declare @AccountId int;

update a set LastProcessDate = getdate()
output inserted.Id into @res(Id)
from (select top (1) * from @t order by LastProcessDate desc) a;

select @AccountId = Id from @res;

-- Returns 3
select @AccountId;

不完全是单线,但接近它,是的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    相关资源
    最近更新 更多