码迷,mamicode.com
首页 > 数据库 > 详细

[转] 基于MySQL的秒杀核心设计(减库存部分)-防超卖与高并发

时间:2015-12-08 18:10:15      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:

商品详情页面的静态化,varnish加速,秒杀商品库独立部署服务器这种就略过不讲了。只讨论库存部分的优化

mysql配置层面的优化可以参考我的这篇文章 《关于mysql innodb引擎性能优化的一点心得》

重点设计在数据库层面。

2张表:

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

字段: id, uid, goods_id, addtime

第二张表:商品表 goods

字段: goods_id   goods_num

方案1:

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语句。极大提升性能

From: http://www.tuicool.com/articles/Bfa63e6

 

[转] 基于MySQL的秒杀核心设计(减库存部分)-防超卖与高并发

标签:

原文地址:http://www.cnblogs.com/imbin/p/5029551.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!