因为现在在外面突然间想到的问题,请大家分析一下 
如我有两个表 
一个是VIP卡表如有 
VIPNO  Amount 
001    1000 一个是Invoice发票表(也就是消费记录) 
ID  VIPNO  Amount Date 我原先的代码为C# 

建立链接 oo 
启动事务 
try 

    Decimal payAmount = 1000; 
    VIPNOInfo  info = new VIPNOInfo(oo,"001") 取出001记录的对像 
    if(info.Amount < payAmount) 
    { 
        throw new Exception("VIP金额不够"); 
    } 
    info.Amount = info.Amount - payAmount; 
    VIP.Update(oo,info); 更新VIP减去收费 
    //添加发票记录 
    InvoiceInfo infoInvoice = new InvoiceInfo(); 
    infoInvoice.VIPNO = info.VIPNO; 
    infoInvoice.Amount =  payAmount; 
    infoInvoice.Date = DateTime.Now; 
    Invoice.Insert(oo,infoInvoice); 

catch(Exception ex) 

    回滚事务 
    Tools.Alert(ex.Message);//报错提示 

finaly 

  结束事务 
  结束链接 
  清空资源 


开始我以为上面的代码是不会有错的,但现在在客户这里就出错了VIP卡收费超额的问题 
我想应该是一个VIP卡在同一时间进行收费的问题 
如两个收费地方,同时对一个VIP卡001进行收费 
1点击收费时, 
if(info.Amount < payAmount) 
通过,但事务还没有提交的时候 
2点击收费 
if(info.Amount < payAmount) 
也通过的时候 
就会造成收费超额的问题 然后我想给VIP添加Updlock但好像也是不行, 
因为好像也会和上面的问题一样 
最后想添加tablock但这样的话效率太差了 大家有什么好的操作流程 --------------------------------------------------------------
在上一贴中
http://topic.csdn.net/u/20090102/15/eb0843a3-0ec7-42bf-96c6-46e42bda9a74.html
大家都说用ROWLOCK
但我回来测试了一下还是不行的
因为如在这里的1点击收费时, 
if(info.Amount < payAmount) 
通过,但事务还没有提交的时候 
2点击收费

就算我上面添加了ROWLOCK但是在2这里还是可以得到他的记录
那么同样这里的判断也会通过
而我要的是,当VIP001在1的地方读取的时候,其他的地方都不可以读取这条记录
直到1操作提交或回滚为止
因为如果1没有提交,而2读到的时候就会1还没有扣钱,而2又去判断钱是否足够
就会造成超额消费的问题,(PS这里要求用程序处理,不要像触发器判断的什么) 

if(info.Amount < payAmount) 
也通过的时候 
就会造成收费超额的问题 
谢谢

解决方案 »

  1.   

    就算我上面添加了ROWLOCK但是在2这里还是可以得到他的记录 
    的意思就是
    VIPNOInfo  info = new VIPNOInfo(oo,"001") 取出001记录的对像 
    原来的语句为
    Select * From VIP Where VIPNO='001'
    变为
    Select * From VIP WITH(ROWLOCK) Where VIPNO='001'谢谢
      

  2.   

    就你的需求来说,就是遇到多用户同时操作同表同记录.只需要进行行锁即可.方法如下,在那帖也已经告诉你了.1 如何锁一个表的某一行A 连接中执行SET TRANSACTION ISOLATION LEVEL REPEATABLE READbegin transelect * from tablename with (rowlock) where id=3waitfor delay '00:00:05'commit tranB连接中如果执行update tablename set colname='10' where id=3 --则要等待5秒update tablename set colname='10' where id<>3 --可立即执行2 锁定数据库的一个表SELECT * FROM table WITH (HOLDLOCK) 
    注意: 锁定数据库的一个表的区别SELECT * FROM table WITH (HOLDLOCK) 
    其他事务可以读取表,但不能更新删除SELECT * FROM table WITH (TABLOCKX) 
    其他事务不能读取表,更新和删除
      

  3.   

    某个用户只要锁住了这条记录,其他用户就不能更新这条记录,除非你使用的是相同的用户.建议你加个字段,用个标记,某个用户在操作这条记录的时候,把标记改为Y , 其他用户不能查询,更改这条记录.
    让该用户操作完毕后,把标记改为N,这样其他用户才能操作这条记录.不过这种做法,一旦遇到该用户长时间操作这条记录时,或操作过程中遇到以外,这条记录的标记不能恢复为N,需要人工干预强制恢复为N,否则其他用户就不能操作这条记录了.
      

  4.   

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READbegin transelect * from tablename with (rowlock) where id=3waitfor delay '00:00:05'commit tran
    ------------------------------------------------
    我用这条语句,我的其他事务都可以读到这条信息啊所以我才会再开贴 来问的谢谢
      

  5.   

    试下把页锁了..SELECT * FROM tablename WITH (paglock,xlock) WHERE id=3
      

  6.   

    RE:
    SELECT * FROM tablename WITH (paglock,xlock) WHERE id=3
    ------------------------------------------------
    这样是可以,
    但是这样好像你tablock一样
    我的其他记录也查询不出来了所以这不个不能,我要的是只锁死这一条的谢谢