zoukankan      html  css  js  c++  java
  • 在高并发买票数量异常问题

    一、一般我们写的买票:查数量,如果有数量就卖出去,库存减一 (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

  • 相关阅读:
    Some ArcGIS Tools
    Optimization Algorithms
    BPTT
    Markdown 简明语法
    【转载】softmax的log似然代价函数(求导过程)
    DP tricks and experiences
    Google Chrome Keyboard Shortcuts
    【转载】如何掌握所有的程序语言
    转 C++ 面向对象程序设计的基本特点
    leetcode 18. 4Sum
  • 原文地址:https://www.cnblogs.com/fps2tao/p/15162645.html
Copyright © 2011-2022 走看看