我有一个SQL Azure数据库,它运行的代码或多或少与此相同:
declare @magic int;
begin tran
select @magic=Magic from MagicTable where MagicId=SomeMagicValue;
update MagicTable set Magic=Magic+SomeValue where MagicId=SomeMagicValue;
commit tran
我确信有时候,如果此代码在具有相同值SomrMagicValue
的两个并发事务中运行,则会发生竞争,并且Magic
列MagicId
中的值会被获取没有增加 - 显然两个事务开始并读取相同的值然后递增相同的值,因此其中一个事务会覆盖另一个事务的结果。
所以我决定添加一些锁定提示。为了验证我的更改,我想首先在测试数据库上重现该问题。所以我创建了一个具有相同模式的表,在那里添加了一些数据并运行以下代码:
declare @counter int;
set @counter=0;
begin tran
while @counter < 10000
begin
declare @magic int;
select @magic=Magic from MagicTable where MagicId=SomeMagicValue;
update MagicTable set Magic=Magic+SomeValue where MagicId=SomeMagicValue;
set @counter = @counter + 1;
end
commit tran
并且此代码在Azure管理门户内部的两个并发事务中运行,每次运行需要几十秒而且从未出现过竞争 - 我的问题没有被重现。
我还尝试了以下变体:
declare @counter int;
set @counter=0;
while @counter < 10000
begin
begin tran
declare @magic int;
select @magic=Magic from MagicTable where MagicId=SomeMagicValue;
update MagicTable set Magic=Magic+SomeValue where MagicId=SomeMagicValue;
commit tran
set @counter = @counter + 1;
end
并且再也没有比赛 - 结果与交易不会并发的结果相同。
问题是 - 我如何找到生产环境中存在问题的原因而不是测试问题?
答案 0 :(得分:0)
begin tran
update MagicTable set Magic=Magic+SomeValue where MagicId=SomeMagicValue;
commit tran
您在第一个查询中的选择是多余的;你从不使用@Magic而你实际上并不需要它。如果你这样做,交易应该处理竞争条件。谁知道?它可能不是一场比赛,而是你的代码中调用DB的错误......