zoukankan      html  css  js  c++  java
  • 高并发超卖问题:测试出现超卖问题和解决方案

    说明:当前测试为thinkphp5环境下的代码、不考虑用户uid问题,只考虑库存问题

    准备:

      1. 新建两个表(goods、orders)

    CREATE TABLE `goods` (
    `id` int NOT NULL AUTO_INCREMENT,
    `name` varchar(30) NOT NULL DEFAULT '',
    `number` int NOT NULL DEFAULT '0',
    `price` int NOT NULL DEFAULT '1',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk
    
    CREATE TABLE `order` (
    `id` int NOT NULL AUTO_INCREMENT,
    `uid` int NOT NULL DEFAULT '0',
    `goods_id` int NOT NULL DEFAULT '0',
    `number` int NOT NULL DEFAULT '0',
    `add_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk
    

      2.插入两条商品数据

    insert into `seo`.`ctx_goods` ( `name`, `number`, `price`) values ( '苹果手机', '10', '1');
    insert into `seo`.`ctx_goods` ( `name`, `number`, `price`) values ( '苹果电脑', '3', '2');
    

      3.购买商品业务代码

    public function order(){
    
        $goods_id = 2;
        $number = 1;
        // 启动事务
        Db::startTrans();
        try{
            $goods = Db::name('goods')->lock(true)->find($goods_id);
            if($goods['number']>0){
                $res1 = Db::name('goods')->where(['id' => $goods_id])->setDec('number', $number);
                $orderData = [
                    'goods_id' => $goods['id'],
                    'uid' => 1,
                    'number' => $number,
                ];
                $res2 = Db::name('order')->insert($orderData);
                if($res1 !==false && $res2){
                    // 提交事务
                    Db::commit();    
                    exit('ok');
                }else{
                    throw new Exception(' 下单失败');
                }
            }else{
                throw new Exception(' 库存不足');
            }
        } catch (Exception $e) {
            // 回滚事务
            Db::rollback();
            exit('error');
        }
        exit;
    }
    

      4. 测试产生超卖问题

      注意:ab测试工具如果没有安装请百度搜索ab工具安装

    ab -c500 -n800 -k http://seo_ctx.cn/portal/index/order

      5. 结果

      商品表数据

        

      订单表数据

        

       

      出现问题原因:

      高并发,导致mysql查询同出来的数据一样,而在同一时间修改没有立即生效,之后这些修改都会被执行。

      从而出现,库存只有3个却生成了3个以上的订单

      解决方案:

      1.设置数据库行锁

      使用行锁,限制同一时间只能进行一个数据修改操作

    将
    $goods = Db::name('goods')->find($goods_id);
    改成
    $goods = Db::name('goods')->lock(true)->find($goods_id);
    

      2.使用redis

      用redis去维护库存

    • redis是基于内存的,内存的读写速度非常快;
    • redis是单线程的,省去了很多上下文切换线程的时间;
    public function order(){
        $goods_id = 2;
        $number = 1;
        $goods = Db::name('goods')->find($goods_id);
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        if($redis->get('goodsNumber:'.$goods_id)!==false){
            //设置初始库存
            $redis->set('goodsNumber:'.$goods_id, $goods['number']);
        }
        // 启动事务
        Db::startTrans();
        try{
            $remain_number = $redis->get('goodsNumber:'.$goods_id);
            if($remain_number>0){
                $redis->decr('goodsNumber:'.$goods_id, 1);
                $res1 = Db::name('goods')->where(['id' => $goods_id])->setDec('number', $number);
                $orderData = [
                    'goods_id' => $goods_id,
                    'uid' => 1,
                    'number' => $number,
                ];
                $res2 = Db::name('order')->insert($orderData);
    
                
                if($res1 !==false && $res2){
                    // 提交事务
                    Db::commit();
                    exit('ok');
                }else{
                    throw new Exception(' 下单失败');
                }
            }else{
                throw new Exception(' 库存不足');
            }
        } catch (Exception $e) {
            // 回滚事务
            Db::rollback();
            exit('error');
        }
        exit;
    }
    

      

      

    小绵羊
  • 相关阅读:
    C#利用反射动态调用类及方法
    系统程序监控软件
    SQL server 2008 安装和远程访问的问题
    sql server 创建临时表
    IIS 时间问题
    windows 2008 安装 sql server 2008
    sql server xml nodes 的使用
    Window 7sp1 安装vs2010 sp1 打开xaml文件崩溃
    CSS资源网址
    Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0
  • 原文地址:https://www.cnblogs.com/lauhp/p/14431949.html
Copyright © 2011-2022 走看看