tp5 并发环境的 解决思路

  • 使用 Redis 得 LIST, 操作 LPOP
  • 使用乐观锁 悲观锁。
  • 目的保持数据操作的 原子性。
mysql 表
fa_flash_product    产品表  		id  num     库存   	version 版本号
fa_flash			成功订单表	id  userid  用户id   msg 描述   
  
redis 队列 
product 产品库存 队列 
/**
     *  初始化 初始化产品库存 
     */
    public function initproduct()
    {
//       dump(Redis::sMembers('product'));
        dump(Redis::sMembers('user_product'));
        Redis::del('product');
        Redis::del('user_product');

        $size = 5;
        for ($i = 0; $i < $size; $i++) {
            Redis::lPush('product', 1);
        }
        if (Redis::lLen('product') == 5) {
            echo '初始化 成功';
        } else {
            echo '初始化 失败';
        }
    }

    /**
     * 抢购
     *
     * 场景:并发环境  秒杀  
     * 10 产品
     *
     */
    public function buyproduct()
    {
        $useid = rand(1000, 2000);

        /**
         * 正常 mysql 没有优化
         * 库存 负数,订单超卖
         */
        $num = db::table('fa_flash_product')->where('id',1)->value('num');
        if ($num > 0) {
            //库存足够
            //库存减少 订单增加
            db::table('fa_flash_product')->where('id',1)->setDec('num');
            db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '抢购成功', 'time' => date('Y-m-d H:i:s')]);
        }


        /**
         *  redis 队列 测试
         *  订单没有超卖
         */
        //移除产品库存队列
        if (Redis::lPop('product')) {
            //成功
            //移除 库存队列;
            db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '抢购成功', 'time' => date('Y-m-d H:i:s')]);
        } else {
            //失败
            db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '秒杀已结束', 'time' => date('Y-m-d H:i:s')]);
        }

        /**
         * 正常 mysql  乐观锁 版本号 version
         * 库存 正常,订单正常
         */
        $find = db::table('fa_flash_product')->where('id', 1)->find();
        if ($find['num'] > 0) {
            //库存足够
            //库存减少 订单增加
            $is_success = db::table('fa_flash_product')->where(['id' => 1, 'version' => $find['version']])->update(['version' => $find['version'] + 1, 'num' => $find['num'] - 1]);
            if ($is_success) {
                db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '抢购成功', 'time' => date('Y-m-d H:i:s')]);
            }
        }
         /**
         * redis   乐观锁
         * watch  监控  开启事务
         *
         */

        Redis::watch('stock');//乐观锁 监视作用 set()  初始值 0
        //开启事务
        $stock = Redis::get('stock'); //库存
        if ($stock) {
            //库存 大约零
            Redis::multi();

            Redis::set('stock', $stock - 1);//扣库存        //返回扣库存后的值

            $res = Redis::exec();//返回事务内,所有命令的返回值,按命令先后排序,当操作别打断时,返回空
            if ($res) {
                //秒杀成功
                db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '抢购成功', 'time' => date('Y-m-d H:i:s')]);
            } else {
                //秒杀失败
                db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '秒杀失败,请重试', 'time' => date('Y-m-d H:i:s')]);
            }
        } else {
            //秒杀结束了
            db::table('fa_flash')->insert(['userid' => $useid, 'msg' => '秒杀结束了', 'time' => date('Y-m-d H:i:s')]);
        }


    }
ab 测试工具

ab.exe  -n50 -c50    

上述暂时简单的处理 库存超卖现象。后续 继续完善 代码

框架 tp5 Redis 操作类 https://github.com/xiucaiwu/tp5redis
简单了解 redis https://m.runoob.com/redis/redis-data-types.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值