我们在做电商项目的时候,经常会遇到抢购秒杀的问题,综合来说主要是两个问题
一,高并发情况下对数据库产生的压力
二,如何避免超卖(库存< 0)的情况。
针对这两个问题来谈下解决思路
一,缓解数据库压力 用 缓存就可以解决 例如redis,memecache 等 就不在多说了。
二,解决这个问题有几种思路(推荐4redis)
1、将库存 goods_store 设置为 unsigned 则当小于0的时候则update失败
sql = update goods set goods_store=goods_store-1 where goods_store>0 and goods_id=11111
2、利用flock 文件排它锁
$fp = fopen('flock.txt', 'w+');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
echo '系统繁忙稍后再试';
die;
}
下单.....
减库存......
3、使用数据库悲观锁(数据库开销比较大)
mysql_query('BEGIN');
$sql = 'select goods_store from goods where goods_id=11111 for update';
$res = mysql_query($sql, $conn);
$row = mysql_fetch_assoc($res,);
if ($row['goods_store'] > 0){
$sql2 = 'update goods set good_store=goods_store-1 where goods_id=11111';
........
}
4、使用redis队列,因为pop操作是原子性的,即使很多用户到达也会依次执行,推荐使用(数据库悲观锁和flock在高并发情况下性能会下降很多)
①将库存存入redis
$amount = 100;
$redis = new Redis();
$res = $redis->connect('127.0.0.1', 6379);
$result = $redis->llen('goods_expensive');//查询已经消费掉的库存
$count = $amount - $result;//剩余库存
for($i=0; $i < $count; $i++){
$redis->lpush('goods_store',1);//遍历存入list
}
echo $redis->llen('goods_store');
②在下单前先判断库存量
$count=$redis->lpop('good_store');
if(!$count){
die('没有库存了');
}
$sql = update goods set goods_store=goods_store-1 where goods_id=11111;
库存减少成功.....