秒杀购物车,库存负数问题

编程有钱人了 2014-05-08 11:13:53
一个小型的商品购物网站,就一个商品列表,商品详细,购物车,订单页等等。整个网站没几句代码

string uid = Request.Cookies["member"].Values["uid"].ToString();
string spid = Request.Form["spid"].ToString();
//u_id是用户ID
//spid 是商品ID
//下面这个语句判断这个人这购物车是否存在这个这个商品 ,如果存在就数量加1,不在重复往购物车里添加重复商品
string getSqlCart = "select count(1) from H_Cart where u_id=" + uid + " and spid=" + spid;
//判断商品库存
string getSqlKc = "select spkc from H_Product where id=" + spid;
if (Convert.ToInt32(DbHelperSQL.GetSingle(getSqlKc)) - 1 < 0)
{
Response.Write(Tool.CreateJson("库存不足!", "2"));
Response.End();
return;
}
//如果这个人的购物车物某个商品存在 就加1 积分=数量*商品积分
if (Convert.ToInt32(DbHelperSQL.GetSingle(getSqlCart)) > 0)
{
string upSql = "update H_Cart set spsl=spsl+1,zjf=(spsl+1)*dhjf where u_id=" + uid + " and spid=" + spid;
DbHelperSQL.ExecuteSql(upSql);
}
else
{
//如果这个商品在某个人的购物车里不存在 直接插入新的一条

//H_CartClass.AddBy 执行的是下面的函数
// public static bool AddBy(string spid,string uid)
//{
// StringBuilder strSql = new StringBuilder();
// strSql.Append("insert into H_Cart(");
// strSql.Append("spid,spmc,spdm,sptp,dhjf,spsl,zjf,spfl,u_id) ");
// strSql.Append("select @spid,spmc,spdm,sptp,dhjf,1,dhjf,spfl,@u_id from H_Product where id=@spid");

// SqlParameter[] parameters = {
// new SqlParameter("@spid", SqlDbType.Int,4),
// new SqlParameter("@u_id", SqlDbType.Int,4)};
// parameters[0].Value = spid;
// parameters[1].Value = uid;

// return DbHelperSQL.ExecuteSql(strSql.ToString(), parameters) > 0;
//}

H_CartClass.AddBy(spid, uid);
}
//不管是插入成功 还是更新成功,库存量都减1
string upSqlProduct = "update H_Product set spkc=spkc-1 where id=" + spid;
DbHelperSQL.ExecuteSql(upSqlProduct);
Response.Write(Tool.CreateJson("商品已经添加到礼品车!", "1"));

在不考虑SQL注入的情况下(后期会做防注入处理,现在是测试阶段,内部人士)
现在的问题,库存居然会出现负数的问题,之前也做过之类的网站,难道是好久没这几这类的网站 我的逻辑不对了?上面的代码 有什么逻辑问题?抢购秒杀的时候,有可能会出现库存负数的问题
数据库用的是SQL2005
...全文
824 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
E次奥 2014-05-09
  • 打赏
  • 举报
回复
你应该在秒杀的时候不要考虑数据库,直接把所有用户的信息存起来,等结束以后,在吧所有信息拿出来进行逻辑判断,得出最终秒杀成功的用户,然后再让那个用户和数据库交互,这样只有一次使用数据库记录!
  • 打赏
  • 举报
回复
队列正解,在内存中排队,返回各自的处理结果.
银-魂 2014-05-09
  • 打赏
  • 举报
回复
mark 集思广益
u010081785 2014-05-09
  • 打赏
  • 举报
回复
同问,有用,谢谢
myhope88 2014-05-09
  • 打赏
  • 举报
回复
逻辑方面的问题吧,或者并发性太高了
grn0515 2014-05-08
  • 打赏
  • 举报
回复
引用 3 楼 wangjun8868 的回复:
[quote=引用 2 楼 grn0515 的回复:] 你应该把这个流程放到存储过程里面去实现,秒杀同时请求这么多,当时判断库存的时候肯定数据没有超,但是你最后执行的库存量都减1,导致你的负数出现,你也可以在最后减1的时候加个where条件,判断库存的数量是否还可以减
楼上两位的意思是 必须写到存储过程里?怎么保证 这个“锁”机制呢?[/quote] 就用存储过程事务就行了吧,你一定要锁的话,你看你是锁行还是页还是表还是数据库咯
  • 打赏
  • 举报
回复
引用 3 楼 wangjun8868 的回复:
[quote=引用 2 楼 grn0515 的回复:] 你应该把这个流程放到存储过程里面去实现,秒杀同时请求这么多,当时判断库存的时候肯定数据没有超,但是你最后执行的库存量都减1,导致你的负数出现,你也可以在最后减1的时候加个where条件,判断库存的数量是否还可以减
楼上两位的意思是 必须写到存储过程里?怎么保证 这个“锁”机制呢?[/quote] 你先保证一个人不可能再1分钟内“秒”两次吧! 满脑子只有“增删改查”的人是写不出真正适当的UI交互程序的,只知道数据库表而已。
编程有钱人了 2014-05-08
  • 打赏
  • 举报
回复
引用 2 楼 grn0515 的回复:
你应该把这个流程放到存储过程里面去实现,秒杀同时请求这么多,当时判断库存的时候肯定数据没有超,但是你最后执行的库存量都减1,导致你的负数出现,你也可以在最后减1的时候加个where条件,判断库存的数量是否还可以减
楼上两位的意思是 必须写到存储过程里?怎么保证 这个“锁”机制呢?
grn0515 2014-05-08
  • 打赏
  • 举报
回复
你应该把这个流程放到存储过程里面去实现,秒杀同时请求这么多,当时判断库存的时候肯定数据没有超,但是你最后执行的库存量都减1,导致你的负数出现,你也可以在最后减1的时候加个where条件,判断库存的数量是否还可以减
jimil 2014-05-08
  • 打赏
  • 举报
回复
秒杀?我以前做过,就像前面有贴子说秒杀功能秒杀99%的程序员,因为要考虑到大并发,而大并发的测试下(一秒100并发数以上),出现负数很正常,因为你没有锁定,即没有队列,比如你的程序有查询和修改两个功能,分别为A\B功能,在客户甲执行A时,同一时间有其它的客户也在执行A,这时如果库存只1,那就会产生有多少客户在执行A就负多少的情况,虽然数据库在队列功能,但你还需要在程序里加上队列功能。 大并发要考虑的东西挺多的,队列是一个,还得考虑延时的问题,还有一个服务器吃不吃得消的问题,比如A为了秒杀在最后一秒用按键精灵等功能模拟鼠标点击100下,你就得SELECT100次,就算你速度快,一次SELECT只要0.001秒,一个客户就得要你0.1秒的服务器反应时间,如果有100个?1000个10000个,你想过你的服务器能吃得消吗?所以你的方法是错误的。
Banianer 2014-05-08
  • 打赏
  • 举报
回复
不管是逻辑上还是代码质量上都不行。 库存和购物车根本是不相干的两个个体。
grn0515 2014-05-08
  • 打赏
  • 举报
回复
KeepSayingNo 2014-05-08
  • 打赏
  • 举报
回复
看了你的代码,做课程设计还行,如果实际应用绝对不行,尤其是面对秒杀这种高并发的应用。应该在秒杀开始前预先将库存表加载到内存中,然后面对用户的需求,直接在内存中操作内存表,在秒杀结束后,批量提交刚才的数据,这样不仅效率高,还不会出现负数这样情况
bwangel 2014-05-08
  • 打赏
  • 举报
回复
不要想着“后期会做防注入处理”,现在先对付一下。漏洞就是这么来的。 能做到秒杀同时有上百个请求,你这个网站已经不能说“小"了。但看代码,还是初学者的搞法。
编程有钱人了 2014-05-08
  • 打赏
  • 举报
回复
引用 11 楼 starfd 的回复:
[quote=引用 8 楼 wangjun8868 的回复:] [quote=引用 6 楼 starfd 的回复:] 你出现负数的原因就在于你的查询spkc跟实际更新这段时间差之内有多个请求进入而已 你可以直接更新库存,根本不用去查spkc,更新成功了,才开始前面的Insert或者Update,然后这部分通过事务保证数据的正确性
好思路,还有一个问题,我判断这个商品是否在购物车中,不存在就插入,存在就更新数量 ,可是当大数量并发的时候,判断失效,如何让用户不能插入重复的商品?[/quote] 这个我不清楚你的购物车有没有设定主键或者对你的数据做索引,假定你有主键ID(聚集索引),根据你这个代码来看的话几个条件加起来具有唯一性约束,你可以select top 1 ID from 购物车来获取ID,然后你再根据是否取到ID来确认是要新增还是更新(更新也用ID来更新),一方面通过去除count来减少sql损耗,另外通过主键来更新会性能更好些,至于你所说的判断失效??在现实中间不可能存在一个用户在短时间内多次快速请求的情况,如果你真要保证成功,那可以对你这几个键值建立唯一性约束,这样就不可能会插入重复值,然后针对那些被唯一约束异常掉的情况,你可以根据规则来判断是放弃这些请求还是对这些请求做补偿机制[/quote] 举个例子吧,张三购物车里已经放了ID为10的商品,李四也可以把这个商品放到购物车,但是张三再次买这个ID为10的商品的时候,就不是插入了,而是更新 我的购物车表基本数据结构是这样的 ID 购车车ID,自动增长,主键 spid 商品ID spmc 商品名称 spsl 商品数量 uid 用户ID 插入购物车表是 条件是 where spid=@spid and uid=@uid 这样来判 每个人的购物车只能购物同一种商品
  • 打赏
  • 举报
回复
引用 8 楼 wangjun8868 的回复:
[quote=引用 6 楼 starfd 的回复:] 你出现负数的原因就在于你的查询spkc跟实际更新这段时间差之内有多个请求进入而已 你可以直接更新库存,根本不用去查spkc,更新成功了,才开始前面的Insert或者Update,然后这部分通过事务保证数据的正确性
好思路,还有一个问题,我判断这个商品是否在购物车中,不存在就插入,存在就更新数量 ,可是当大数量并发的时候,判断失效,如何让用户不能插入重复的商品?[/quote] 这个我不清楚你的购物车有没有设定主键或者对你的数据做索引,假定你有主键ID(聚集索引),根据你这个代码来看的话几个条件加起来具有唯一性约束,你可以select top 1 ID from 购物车来获取ID,然后你再根据是否取到ID来确认是要新增还是更新(更新也用ID来更新),一方面通过去除count来减少sql损耗,另外通过主键来更新会性能更好些,至于你所说的判断失效??在现实中间不可能存在一个用户在短时间内多次快速请求的情况,如果你真要保证成功,那可以对你这几个键值建立唯一性约束,这样就不可能会插入重复值,然后针对那些被唯一约束异常掉的情况,你可以根据规则来判断是放弃这些请求还是对这些请求做补偿机制
jimil 2014-05-08
  • 打赏
  • 举报
回复
不,不,楼主你整个思路都是错的,大并发下不可能再使用数据库作为修改数据的载体,只能以内存为载体,不然根本解决不了大并发下产生的延时以及你的购物车需求,你需要将购物车这些都记录在内存中,并加上锁或者无锁来实现,由于关系到核心代码的问题,我并不能直接给你代码,但可以给你一些资源,你可以在百度搜索:c# 大并发 队列 里面有锁,无锁的队列信息,你可以参考一下,但总的一句,秒杀是不能以数据库为载体的,无论是储存过程还是什么,打开数据库总要时间的,而队列一多,造成的假死足够你的项目一上线就OVER
-Arvin 2014-05-08
  • 打赏
  • 举报
回复
购物车直接往数据库放?
编程有钱人了 2014-05-08
  • 打赏
  • 举报
回复
引用 6 楼 starfd 的回复:
你出现负数的原因就在于你的查询spkc跟实际更新这段时间差之内有多个请求进入而已 你可以直接更新库存,根本不用去查spkc,更新成功了,才开始前面的Insert或者Update,然后这部分通过事务保证数据的正确性
好思路,还有一个问题,我判断这个商品是否在购物车中,不存在就插入,存在就更新数量 ,可是当大数量并发的时候,判断失效,如何让用户不能插入重复的商品?
  • 打赏
  • 举报
回复
你出现负数的原因就在于你的查询spkc跟实际更新这段时间差之内有多个请求进入而已 你可以直接更新库存,根本不用去查spkc,更新成功了,才开始前面的Insert或者Update,然后这部分通过事务保证数据的正确性
加载更多回复(1)

62,074

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧