当前位置: 代码迷 >> Sql Server >> select查询统计后INSERT,怎么防止赃数据的发生
  详细解决方案

select查询统计后INSERT,怎么防止赃数据的发生

热度:97   发布时间:2016-04-24 09:55:27.0
select查询统计后INSERT,如何防止赃数据的发生?
表A
字段:
a_id(主键)
totalquantity(int类型/B表quantity字段值的sum汇总)

表B
字段:
b_id(主键)
a_id(外键)
quantity(int类型)
-----------------------------------------
处理程序的伪代码如下:

function buyadd(id,quantity)
{
        变量 m=执行查询语句(select totalquantity from a where a_id=id) //获取目前总数量
        变量 n=执行查询语句(select sum(quantity) from b where a_id=id) //获取数量汇总
        
        if(m-n>0)
        {
                执行语句(insert into b(b_id,a_id,quantity)values(b_id,id,quantity));
                return true;
        }
        return false;
}

========================================================
好了问题出现了,就是当执行buyadd方法时,一旦是多用户访问的情况下很容易读出赃数据,造成多插入的问题。
(比如2个用户同时读取的时候都发现m-n>0,然后就都insert, 直接就导致n<m的情况出现)

也想过select的时候加锁,但是会引起并发延迟的问题,请问大家都怎么处理这个问题的呢?


 
------解决思路----------------------
可否设置等待延时?第一个用户读取后,延时几秒钟,第二个用户再读取数据应该就不会出现这种情况了!
------解决思路----------------------
你不和将要插入的quantity比较?单人更新也会导致 n>m 的啊!

建议a表加个remainquantity 字段,表示还可以添加的数量。
下面用SQL描述,你自己翻译成对应的程序。
BEGIN TRAN

update a
   set remainquantity = remainquantity - @quantity
 where a_id=id
   and remainquantity >= @quantity -- 这个很关键

IF @@ROWCOUNT=0
BEGIN
    ROLLBACK TRAN
END
ELSE
BEGIN
    insert into b(b_id,a_id,quantity)values(b_id,id,@quantity))
    COMMIT TRAN
END

原理参考类似问题的帖子sql事务
------解决思路----------------------
类似问题面对并发的时候,只有也只能通过加锁来解决
楼主参考下具体的加锁方法
http://www.cnblogs.com/nzperfect/archive/2011/09/27/2193143.html#2973795
  相关解决方案