2

首先,我不需要 100% 防止死锁,但我能做的任何事情来减少它们都会很好。

我有两张桌子SourceDest. Source 中有许多唯一值,我需要从中请求一个新值,Source并在这样做时将其移动到Dest.

我有以下sql:

begin tran
    declare @value
    select top 1 @value = [value] from [source]
    delete from [Source] where [value]=@value
    insert into [Dest] ([Value]) values (@value)
    select @value
commit tran

当多个用户获得同一value行时,这偶尔会引发死锁。我该如何预防/减少这种情况?

我正在使用 SQL Server 2008

顺便说一句,还有其他列SourceDest我正在阅读/写入。为了简洁起见,这是一个简化。

谢谢

4

2 回答 2

3

您可以通过在 DELETE 命令中使用OUTPUT子句来避免这种竞争条件,因为它将从源中删除值并在单个原子操作中返回它。我制作了以下脚本来演示这个概念:

-- dummy data
CREATE TABLE #source (mycolumn INT);
CREATE TABLE #destination (mycolumn INT);

INSERT #source VALUES (1);
INSERT #source VALUES (2);
INSERT #source VALUES (3);
GO

-- stored procedure to demonstrate concept
CREATE PROCEDURE move
AS BEGIN
    BEGIN TRANSACTION;

    DECLARE @tmp TABLE (mycolumn INT);
    DELETE TOP(1) #source OUTPUT DELETED.mycolumn INTO @tmp(mycolumn);

    INSERT #destination (mycolumn) OUTPUT INSERTED.mycolumn
    SELECT mycolumn
    FROM @tmp;

    COMMIT;
END
GO

-- testing
EXEC move;
GO -- remove from 1 from #source, insert 1 into #destination, returns 1

EXEC move;
GO -- remove from 2 from #source, insert 2 into #destination, returns 2

EXEC move;
GO -- remove from 3 from #source, insert 3 into #destination, returns 3
于 2012-05-02T16:42:26.857 回答
1

XLOCK你可以用SELECT语句抓住一个

begin tran
    declare @value
    select top 1 @value = [value] from [source] with (XLOCK)
    delete from [Source] where [value]=@value
    insert into [Dest] ([Value]) values (@value)
    select @value
commit tran
于 2012-05-02T17:38:57.847 回答