在高并发买票数量异常问题
作者:互联网
一、一般我们写的买票:查数量,如果有数量就卖出去,库存减一 (controller的sellTicket方法)
//测试买票软件库存问题 public function sellTicket() { $test = Db::name('test')->find(1); if($test['nums']>0){//买票 $num = $test['nums']-1; $res = Db::name('test')->where('id', 1)->update(['nums'=>$num]); echo "买票成功,剩余数".$num; }else{ echo "没有票了".$test['nums']; } //参考:https://blog.csdn.net/u011277123/article/details/78913649 //测试apache的并发测试 ab工具:ab -n 200 -c 20 http://localhost/index.php (共执行200次并发是20) }
数据很简单如下(有100张票)
现在我们执行下并发在20共请求40次,的库存剩余是多少(当然剩余是60是我们的预期)
=======果然不是我们要的结果,我们理想的答案是60,然而数据库剩余库存是63。
不难理解,有3个请求是同事发生的,它们读了相同的剩余库存,都减了1,写在了剩余量里面.
=======怎么避免这种情况呢?其实通用的方法有两种(一个数据库锁 [排它锁],另一个是文件锁)
二、我们用数据库锁来解决刚才的问题
public function sellTicket() { //语法:LOCK TABLES t1 WRITE, t2 READ, ...; //加锁 //Db::query("LOCK TABLES think_test WRITE"); $test = Db::name('test')->lock(true)->find(1);//用了thinkphp里面带的锁 if($test['nums']>0){//买票 $num = $test['nums']-1; $res = Db::name('test')->where('id', 1)->update(['nums'=>$num]); echo "买票成功,剩余数".$num; }else{ echo "没有票了".$test['nums']; } //UNLOCK TABLES; //去锁 //Db::query("UNLOCK TABLES;"); //参考:https://blog.csdn.net/u011277123/article/details/78913649 //测试apache的并发测试 ab工具:ab -n 200 -c 20 http://localhost/index.php (共执行200次并发是20) }
结果是正确的:(100票进行40个请求20的并发测试)
三、我们来用文件锁,解决并发的问题
//测试买票软件库存问题 public function sellTicket() { $file = fopen(__DIR__.'/lock.txt','w+'); if(flock($file,LOCK_EX)){ //TODO 执行业务代码 $test = Db::name('test')->find(1);//用了thinkphp里面带的锁 if($test['nums']>0){//买票 $num = $test['nums']-1; $res = Db::name('test')->where('id', 1)->update(['nums'=>$num]); echo "买票成功,剩余数".$num; }else{ echo "没有票了".$test['nums']; } flock($file,LOCK_UN);//解锁 } fclose($file);//关闭文件 //参考:https://blog.csdn.net/u011277123/article/details/78913649 //测试apache的并发测试 ab工具:ab -n 200 -c 20 http://localhost/index.php (共执行200次并发是20) }
通过命令 结果也是 预期结果.
数据库锁:https://blog.csdn.net/qq_35642036/article/details/89554721
文件锁参考:https://www.cnblogs.com/zhouguowei/p/9708380.html
标签:20,nums,Db,并发,num,test,买票,异常 来源: https://www.cnblogs.com/fps2tao/p/15162645.html