首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

ROWLOCK 失效,两个请求同时进行事务 重复写入数据

2012-09-10 
ROWLOCK 失效,两个请求同时进行事务 重复写入数据 求救说明:UPDATE Deposits WITH (ROWLOCK) SET status4

ROWLOCK 失效,两个请求同时进行事务 重复写入数据 求救
说明:
  UPDATE Deposits WITH (ROWLOCK) SET status=4,UpdateTime=getdate() WHERE DepositId=@billno;

  DepositId请求过来,会存在两次提交的可能,所以,我做了行锁定处理,一直运行良好,没有问题

  近一个月,频繁出现了3次重复写入的问题。

  更新时锁定行,但出现同一DepositId 两次操作,写入重复数据

  怀疑是两个请求条数据 同时进入事务,行锁没有起做用
   
  那位大侠有空,帮忙指点一下,感激不尽。。。。

SQL code
set ANSI_NULLS ONset QUOTED_IDENTIFIER ONgo--功能:online_Deposit加款 ALTER proc [dbo].[P_Online_Deposit_Process] @billno varchar(50),  --存款编号 @UpdateBy varchar(50), @UpdateIp varchar(64), @amount money, @Remark varchar(50), @TypeID intas  declare @beforeBalance money;  declare @afterBalance money;  declare @TrueDeposited money;  declare @UserId uniqueidentifier ;  declare @status int;--lv等级判断参数  declare @depositnum   int;  declare @totaldeposit int;  declare @levelid  int;   declare @beforeLevelid  int; BEGIN        SET NOCOUNT ON;     set xact_abort on;         If not exists(SELECT  TrueDeposited,DepositId FROM Deposits WHERE  DepositId=@billno and TrueDeposited=@amount)           begin           select '1' flag,N'交易失败:不存在此订单或交易金额与数据库中不相同.' msg           RETURN;        end     SELECT @UserId=UserId,@status=status  FROM Deposits  WHERE DepositId=@billno;   if(@status=4 or @status=5) begin        select '1' flag,N'交易失败:该记录已经处理完成,不允许在次操作.' msg        return;    end; if(@TypeID=1) begin     if(@status=1) begin            Begin Tran ;--充值 事务处理开始               --更新存款记录状态       UPDATE Deposits  WITH (ROWLOCK)  SET status=4,UpdateTime=getdate()   WHERE DepositId=@billno;         select @beforeBalance=Balance FROM Users WHERE UserId=@UserId;--之前主帐户余额         --写入存款记录状态更新日志    insert into log_UsersDeposit (Id,Remark,TranID,status,UserId,UpdateBy,UpdateIp,UpdateTime) values (newid(),@Remark,@billno,'Success',@UserId,'IPS',@UpdateIp,getdate());        --对主帐号进行实际充值        UPDATE Users SET Balance=Balance+@amount,totaldeposit=totaldeposit+@amount,depositnum=depositnum+1,UpdateTime=getdate(),Updateby=@UpdateBy  WHERE UserId=@UserId;          select @afterBalance=Balance FROM Users WHERE UserId=@UserId;--充值之后主帐户余额                     select @totaldeposit=(SELECT totaldeposit FROM Users WHERE UserId=@UserId);--totaldeposit         select @depositnum=(SELECT depositnum FROM Users WHERE UserId=@UserId);--depositnum         select @beforeLevelid=(SELECT UserLevel FROM Users WHERE UserId=@UserId);--beforeLevelid        select @levelid=(SELECT top 1 levelid FROM T_LevelMap  where depositnum<=@depositnum and totaldeposit<=@totaldeposit  order by levelid desc);--UserLevel         UPDATE Users SET UserLevel=@levelid WHERE UserId=@UserId  and @levelid>@beforeLevelid;           -----------------写入主帐户变动日志开始----------        insert into log_UsersBlance  (Id,Remark,TranID,tranType,Operating,Amt,beforeBalance,afterBalance,UserId,UpdateBy,UpdateIp,UpdateTime) values           (newid(),@Remark,@billno,1,'+',@amount,@beforeBalance,@afterBalance,@UserId,@UpdateBy,@UpdateIp,getdate());                       if (@@error <> 0) begin                select '1' flag,N'交易失败:该记录已经处理完成.' msg                rollback tran ;                return;             end        Commit Tran;  --事务处理结束                     select '0' flag,N'交易成功: Sussce.' msg      end  end else if(@TypeID=5) begin    Begin Tran ;      UPDATE Deposits WITH (ROWLOCK)  SET  status=5,UpdateTime=getdate(),Updateby=@Updateby  where  DepositId=@billno;        --写入存款记录状态更新日志      insert into log_UsersDeposit  (Id,Remark,TranID,status,UserId,UpdateBy,UpdateIp,UpdateTime) values       (newid(),@Remark,@billno,'Reject',@UserId,@Updateby,@UpdateIp,getdate()) ;                       if (@@error <> 0) begin                select '1' flag,N'交易失败:已经处理完成' msg                rollback tran ;                return;             end      Commit Tran;              select '0' flag,N'交易失败: Reject.' msg   endEND 



[解决办法]
有个疑问,你只是对update进行行锁定,又不是insert,为什么会有重复数据呢?
[解决办法]
如楼上疑问
[解决办法]
你的锁的用法必然会出问题的,以前正常只能说明并发量不足或者数据量不足或者运气好
[解决办法]
建议:
使用rowlock的时候,建议结合holdlock一起使用。

当然你可以提高事务隔离级别,
e.g.在存储过程开始位置声明:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

[解决办法]
xlock,rowlock也不一定能锁足行
一般采用的方法是xlock,paglock来锁行。
[解决办法]
锁应该加在取值的哪一行

SELECT @UserId=UserId,@status=status FROM Deposits WHERE DepositId=@billno;

热点排行