http://f./thread-485176-1-1.html (出处: 炼数成金) from: http://www./articles/Bfa63e6 商品详情页面的静态化,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语句。极大提升性能 |
|