现有一改变用户余额的存储过程,大致如下:
Create PROCEDURE [dbo].[proc_ChangeBalance]
@userid int,--用户编号
@changemoney decimal(18,2)--改变金额,正为收入,负为支出
AS
BEGIN
declare @curBalance decimal(18,2) = 0 --当前余额
declare @newBalance decimal(18,2) = 0 --改变后余额
declare @curAccountId int = -1--当前账户编号
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-----------------------------------------开始事务----------------------------
begin transaction
save tran changeBalance
--获取当前账户信息
select @curAccountId = ID, @curBalance =ISNULL(Balance,0) from UserBalance with(rowlock) where UserId=@userid --余额不足
if(@changemoney < 0 and @curBalance < ABS(@changemoney))
begin
rollback transaction changeBalance
commit transaction
return
end
declare @error int = 0--错误信息
set @newBalance = @curBalance + @changemoney
--执行账户修改
update UserBalance with(rowlock) set Balance = @newBalance where ID=@curAccountId
set @error = @error + @@ERROR
--记录账户流水日志
Insert Into BalanceLog
values
(@userid,@curBalance,@changemoney,@newBalance,getdate())
set @error = @error + @@ERROR if(@error = 0)
begin
commit transaction
end
else
begin
rollback transaction changeBalance
commit transaction
end
END现在的问题是在某些并发的时候,两次执行取到的当前余额都是一样的,导致最后只有一个执行有效,如果没有生效那个执行是扣钱的话,那最终就没有扣钱,如果是加钱的话,就没有加钱了.怎么锁定这个执行,让第二次执行的时候始终等待第一个执行完成,这样第二次执行的时候取到的当前余额才是真实有效的.谢谢!
Create PROCEDURE [dbo].[proc_ChangeBalance]
@userid int,--用户编号
@changemoney decimal(18,2)--改变金额,正为收入,负为支出
AS
BEGIN
declare @curBalance decimal(18,2) = 0 --当前余额
declare @newBalance decimal(18,2) = 0 --改变后余额
declare @curAccountId int = -1--当前账户编号
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-----------------------------------------开始事务----------------------------
begin transaction
save tran changeBalance
--获取当前账户信息
select @curAccountId = ID, @curBalance =ISNULL(Balance,0) from UserBalance with(rowlock) where UserId=@userid --余额不足
if(@changemoney < 0 and @curBalance < ABS(@changemoney))
begin
rollback transaction changeBalance
commit transaction
return
end
declare @error int = 0--错误信息
set @newBalance = @curBalance + @changemoney
--执行账户修改
update UserBalance with(rowlock) set Balance = @newBalance where ID=@curAccountId
set @error = @error + @@ERROR
--记录账户流水日志
Insert Into BalanceLog
values
(@userid,@curBalance,@changemoney,@newBalance,getdate())
set @error = @error + @@ERROR if(@error = 0)
begin
commit transaction
end
else
begin
rollback transaction changeBalance
commit transaction
end
END现在的问题是在某些并发的时候,两次执行取到的当前余额都是一样的,导致最后只有一个执行有效,如果没有生效那个执行是扣钱的话,那最终就没有扣钱,如果是加钱的话,就没有加钱了.怎么锁定这个执行,让第二次执行的时候始终等待第一个执行完成,这样第二次执行的时候取到的当前余额才是真实有效的.谢谢!
改为:
SET TRANSACTION ISOLATION LEVEL serializable