【发布时间】:2015-04-08 04:11:13
【问题描述】:
现在,我正在尝试使用用户提供的数字来增加 SQL Server 中的连续数字。
当多个用户以相同的数字同时插入一行时,我遇到了问题。
我尝试更新用户提供给临时表的数字,并且我希望当我以相同的条件更新同一个表时,SQL Server 将锁定对该行的任何修改,直到当前更新完成,但事实并非如此。
这是我使用的更新语句:
UPDATE GlobalParam
SET ValueString = (CAST(ValueString as bigint) + 1)
WHERE Id = 'xxxx'
你能告诉我有什么方法可以强制其他更新命令等到当前命令完成吗?
这是我的全部命令:
DECLARE @Result bigint;
UPDATE GlobalParam SET ValueString = (SELECT MAX(Code) FROM Item)
DECLARE @SelectTopStm nvarchar(MAX);
DECLARE @ExistRow int
SET @SelectTopStm = 'SELECT @ExistRow = 1 FROM (SELECT TOP 1 Code FROM Item WHERE Code = '999') temp'
EXEC sp_executesql @SelectTopStm, N'@ExistRow int output', @ExistRow output
IF (@ExistRow is not null)
BEGIN
DECLARE @MaxValue bigint
DECLARE @ReturnUpdateTbl table (ValueString nvarchar(max));
UPDATE GlobalParam SET ValueString = (CAST(ValueString as bigint) + 1)
OUTPUT inserted.ValueString INTO @ReturnUpdateTbl
WHERE [Id] = '333A8E1F-16DD-E411-8280-D4BED9D726B3'
SELECT TOP 1 @MaxValue = CAST(ValueString as bigint) FROM @ReturnUpdateTbl
SET @Result = @MaxValue
END
ELSE
BEGIN
SET @Output = 999
END
END
我把上面的代码写成一个存储过程。
这是我插入一项时的真实代码:
DECLARE @IncrementResult BIGINT
EXEC IncrementNumberUnique
, (some parameters)..
,@Result = @IncrementResult OUTPUT
INSERT INTO ITEM (Id, Code) VALUES ('xxxx', @IncrementResult)
我创建了 3 个线程并让它同时运行。
返回结果:
Id Code
1 999
2 1000
3 1000
谢谢
【问题讨论】:
-
当您尝试此更新时,带有
Id = 'xxx'的行实际上将在更新其值所需的时间内被独占锁定,然后该锁定将在事务提交(或滚动)时释放背部)。只有 一行 您正在更新 - 而不是整个表。因此,另一行的第二个UPDATE命令(具有不同的Id值)将能够继续 - 这是一件好事! -
@marc_s:感谢您的回复。但是我有两个线程试图更新这一行(相同的 ID),我不知道为什么第二次更新不等待第一次完成。我已经尝试过 ROWLOCK 但我仍然得到重复的值
-
只是这个“原子”
UPDATE将强制第二个线程等待 - 但这真的是你的整个语句吗?会不会是你先有SELECT?那不会被锁定.... -
@marc_s :我发布了整个声明。你有什么想法吗?
-
正如怀疑的那样 - 它不是单个原子
UPDATE_ 因此它很容易出现重复(如您所见)。那么为什么不让数据库使用INT IDENTITY列来处理所有这些混乱的细节并完成它????
标签: sql sql-server locking increment