电商并发减库存设计,如何做到不超卖

开发 架构
高并发的秒杀活动中,通过查询数据库判断是否还有库存,然后对库存字段进行增减,极易出现库存超出或者库存为负的情况,一般来说有3中解决办法(数据库表加锁,memche缓存,redis队列)。

前言

高并发的秒杀活动中,通过查询数据库判断是否还有库存,然后对库存字段进行增减,极易出现库存超出或者库存为负的情况,一般来说有3中解决办法(数据库表加锁,memche缓存,redis队列);

我们这里使用redis来解决问题

1、思路:

1)触发开始开团的同时,把库存数量更新到id对应的队列上去(定时更新,或者手动更新)

2)用户请求接口,如果队列长度>0,移除一个队列记录,同时对数据库进行相应操作

3)如果队列长度<=0,拦截用户的访问,返回‘无库存’

2、重点设计在数据库层面

2张表:

第一张:判重表(buy_record),该用户有没秒杀过该商品

字段: id, uid, goods_id, addtime

第二张表:商品表 goods

字段:goods_id goods_num

方案一

start transaction;
  select id from buy_record where uid=$uid and goods_id=$goods_id;
  if(结果不为空)
      抛异常,回滚。
  insert into buy_record。。。
  if(受影响行数<=0)
          抛异常,回滚。。。  
  select goods_num from goods where goods_id=$good_id;
  if(库存<=0)
          抛异常,回滚。。。  
  update goods set goods_num=goods_num-1 where goods_id=$goods_id;
  if(受影响行数<=0)
      该方法在高并发下几乎必然导致超卖。当库存为1的时候刚好多个用户同时    select goods_num from goods where goods_id=$good_id;此时库存刚好大于0,做update操作的时候必然减到小于0.  同时上面进行是否秒杀过的判重同样会出现类似问题

方案二

start transaction;
    select id from buy_record where uid=$uid and goods_id=$goods_id          for       update        ;  
if(结果不为空)
    抛异常,回滚。
insert into buy_record。。。
if(受影响行数<=0)
    抛异常,回滚。。。
    select goods_num from goods where goods_id=$good_id    for update    ;  
if(库存<=0)
    抛异常,回滚。。。
    update goods set goods_num=goods_num-1     where goods_id=$goods_id    ;  
if(受影响行数<=0)
    抛异常,回滚。。。
该方法有效的防止了超卖,但是在每次select的时候加上了排它锁,每次select操作都会被堵塞    ,并发性能大大降低。

方案三

对(uid,goods_id)加唯一索引!!      
  start transaction;
      insert into buy_record。。。  
  if(唯一索引报错?)
      抛异常,已经秒过了,回滚。。。
            update goods set goods_num=goods_num-1                         where goods_id=$goods_id          and                goods_num>0            ;      
  if(受影响行数<=0)
      抛异常,商品秒完了,回滚。。。

该方法完美的解决了超卖与select排它锁导致的并发低的问题,并且4个sql缩减成2个sql语句。极大提升性能。

责任编辑:武晓燕 来源: 程序员编程日记
相关推荐

2022-09-19 09:49:17

MCube网络引擎

2021-05-24 10:55:05

Netty单机并发

2024-12-04 13:52:30

2022-09-09 08:41:43

Netty服务端驱动

2017-09-11 16:34:00

2011-11-09 15:49:52

API

2021-08-02 09:01:05

MySQL 多版本并发数据库

2009-11-20 11:37:11

Oracle完全卸载

2016-01-08 10:03:07

硅谷通吃互联网

2019-08-08 10:18:15

运维架构技术

2021-06-09 18:52:05

方案设计库存数

2010-03-30 10:44:05

Nginx启动

2013-04-22 10:34:46

用户体验设计UED认知负荷

2020-11-10 09:05:45

用户画像苏宁

2024-06-20 07:59:49

2024-07-25 09:05:35

2017-11-14 08:25:36

数据库MySQL安全登陆

2011-06-22 09:45:46

JavaScriptAPI

2021-06-04 05:54:53

CIO数据驱动数字转型
点赞
收藏

51CTO技术栈公众号