//本文需要注意的地方
$num = Db::name('bingfa')->where('id',1)->lock(true)->value('num'); //这里我加了lock锁住本次操作,其他操作需要等待本次操作结束后才能操作
SELECT `num` FROM `api_bingfa` WHERE `id` = 1 LIMIT 1 FOR UPDATE //mysql 源代码,for update就是lock
//这个是日志记录以下测试共用
public function insertLog($log){
file_put_contents("log.txt",$log."\n", FILE_APPEND);
}
//高并发测试工具ab,-n 总请求数 -c 每次的请求数 url你的网址
ab -n 1000 -c 100 -k url
1.没有加任何操作的情况下,货存为负
2.使用事务操作
$id = 1;
Db::startTrans();
$num = Db::name('bingfa')->where('id',1)->lock(true)->value('num');
if($num>0){
//库存减少
$res = Db::name('bingfa')->where('id',1)->setDec('num');
if($res){
$this->insertLog('库存减少成功'.$id);
Db::commit();
}else{
$this->insertLog('库存减少失败');
}
}else{
$this->insertLog('库存不足');
Db::rollback();
}
return 'success';
没有出现负数情况,刚好一百个人获取到
3.redis队列操作
//设置总库存
$store=100;
//tp里已经配置好了,直接调用
$redis = new Redis();
//查看队列里以后的货物
$res = $redis->llen('goods_store');
//需要入队的货物
$count=$store-$res;
for($i=0;$i<$count;$i++){
$redis->lpush('goods_store',"1");
}
//这里就是用户购买商品出队
$count=$redis->lpop('goods_store');
//出队查看货物是否存在,不存在则无货物
if(!$count){
$this->insertLog('error:no store redis');
return;
}
//存在则提取货物
$res = Db::name('bingfa')->where('id',1)->setDec('num');
$this->insertLog('库存减少成功1');
没有出现库存负数的情况
以上二种方式都可以解决高并发的问题