订单并发商品超卖问题解决

问题:商品超卖(库存数出现负数)。

模拟并发:

goods商品表:

/**
 * 下单
 * @return string
 * @throws \yii\db\Exception
 */
public function actionIndex()
{
    $redis = Yii::$app->redis; // 使用redis做一些统计
    $redis->incr(‘total‘); // 自增(记录一共成功进来了多少个请求)

    //$redis->del(‘total‘);
    //$redis->del(‘update‘);
    //$redis->del(‘success‘);
    //$redis->del(‘faild‘);die;
    //var_dump(‘total:‘ . $redis->get(‘total‘));
    //var_dump(‘success: ‘ . $redis->get(‘success‘));
    //var_dump(‘faild:‘ . $redis->get(‘faild‘));
    //var_dump(‘update:‘ . $redis->get(‘update‘));die;

    $model = Goods::find()->where([‘id‘ => 1])->one(); // 购买的商品信息
    if ($model->number > 0) { // 判断库存是否大于0
        $redis->incr(‘update‘); // 记录并发时进来的请求数

        $result = Yii::$app->getDb()->createCommand("UPDATE goods SET     number = number - 1 WHERE id = 1 LIMIT 1")->execute(); // 更新库存

        if($result){ // 更新成功插入订单数据, 这里应该是要写事务的

            $orderModel = new Orders();
            $orderModel->price = $model->price;
            $orderModel->name = $model->name;
            $orderModel->create_time = time();
            $orderModel->save(false);

            $redis->incr(‘success‘); // 记录更新成功数

        }else{
            $redis->incr(‘faild‘); // 记录更新成功数
        }
    }
    die(‘成功‘);
    return $this->render(‘index‘);
}

k6压测:

最后商品库存变成了 -3 (超卖了3)

压测记录结果: 

压测并发有点少,因为我机子最大打开2048个文件,网络用的4g,也受网络影响等因素,如果压测的本地机器和网络好更准些。

回顾:如果 $result = Yii::$app->getDb()->createCommand("UPDATE goods SET number = number - 1 WHERE id = 1 LIMIT 1")->execute(); // 更新库存 这一句不是这么更新 set `库存字段` = `库存字段` - 1 ,而是计算好再更新进去 $number = $number -1 就不会出现负数或设置库存字段属性为UNSINGED,但不能真正解决掉问题,因为实际还是多执行3次,这么写是为了测试负数,也就是这句里面

if ($model->number > 0) { 实际执行了103次,超出100的库存, 也就是说当 库存$model->number等于1时 同时并发3请求执行到这里,这3个并发查询出来的库存都为1的时候都执行了更新库存导致的。
解决超卖问题:
  /**
     * 提前把商品库存入队列
     */
    public function actionSetStore()
    {
        $redis = Yii::$app->redis;
	    $model = Goods::find()->where([‘id‘ => 1])->one(); //商品信息

        for ($i = 0; $i < $model->number; $i++)
        {
            $redis->lpush(‘goods_store‘, 1);
        }
    }

    /**
     * 下单
     * @return string
     * @throws \yii\db\Exception
     */
    public function actionIndex()
    {
        $redis = Yii::$app->redis; // 使用redis做一些统计
        $count = $redis->lpop(‘goods_store‘); // 出队列

        if ($count) { // 判断库存是否出完队列
            // 更新库存等逻辑
            $result = Yii::$app->getDb()->createCommand("UPDATE goods SET number = number - 1 WHERE id = 1 LIMIT 1")->execute(); 

        }
        else {
            die(‘卖完了‘);
        }
        die(‘成功‘);
    }

大佬们轻拍,如果有什么地方讲得不对或你有什么好的方案解决谢谢提出。


 

原文地址:https://www.cnblogs.com/qq260101081/p/10897599.html

时间: 2024-10-09 10:12:19

订单并发商品超卖问题解决的相关文章

以商品超卖为例讲解Redis分布式锁

本案例主要讲解Redis实现分布式锁的两种实现方式:Jedis实现.Redisson实现.网上关于这方面讲解太多了,Van自认为文笔没他们好,还是用示例代码说明. 一.jedis 实现 该方案只考虑Redis单机部署的场景 1.1 加锁 1.1.1 原理 jedis.set(String key, String value, String nxxx, String expx, int time) key: 使用key来当锁,因为key是唯一的; value: 我传的是唯一值(UUID),很多童鞋

PHP并发、超卖处理

做电商网站,经常会有各种秒杀和热门商品,所以高并发的处理一直是电商最重要的事情.这里记录下当初自己是如何处理的 写在前面: 1.本文设计到的并发处理均是针对纵向,不针对横向扩展,即只设计从PHP层面到数据库层面的处理,不涉及多台服务器,集群.大带宽等的横向设计. 2.本文中涉及到的高并发并不是淘宝京东等几百万几千万等的高并发,仅仅只是普通最多上万的并发处理 3.本文不对悲观锁乐观锁做设计 问题: 普通电商中的秒杀中的并发问题,超卖问题 实例:商品数量为100,秒杀人数为10000,整点开始秒杀

避免商品超卖的4种方案

原始方案(失败):在每次下订单前我们判断促销商品的数量够不够,不够不允许下订单,更改库存量时加上一个条件,只更改商品库存大于0的商品的库存,当时我们使用ab进行压力测试,当并发超过500,访问量超过2000时,还是会出现超卖现象. public function buyOne() { $shop = Shop::find(1); if ($shop->number > 0) { DB::update("update shop set number = number - 1 where

商城商品超卖处理

首先环境介绍下:商城商品可能存在几个端(PC.APP),其次每个端对应的服务端又可能做了负载均衡(即也有多个服务端). 要实现的目标和功能:保证商品不会出现超卖的情况.超卖商品后,无法对商品进行发货,是一种不负责任的行为. 方案实现讨论流程 "要实现不超卖,首先商品库存的扣减不能使用框架进行更新,因为框架是设置值,如果在这段时间,又有人购买了,则商品库存必然会出现问题.要采用手写SQL方式.并且sql中还要判断是否大于等于指定的购买量." UPDATE `SKU_Info` SET s

超卖频发or商品滞销?压倒卖家的最后一根稻草竟是库存!

超卖频发or商品滞销?压倒卖家的最后一根稻草竟是库存! 云南逸神生态茶业有限公司便是一家从最初的单体销售到目前的生产.加工.销售一体化经营,并拥有60多家遍布云南省内.省外城市的直营专卖店.想要发展壮大,除了产品品质之外,更重要的是方法,拥有60多家门店的"逸神"已经出现了库存不准导致的商品超卖,商品滞销带来的库存积压,如无法解决这些问题,发展壮大只能是个遥远的梦.逸神管理者具有长远的眼光,他认为想要把逸神发展成为更大的连锁企业,不仅依靠逸神的销售团队,同时还要借助先进的管理工具实现对

秒杀的性能和超卖

一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其中[抢订单]这个环节是最考验业务提供方的抗压能力的. 抢订单环节一般会带来2个问题: 1.高并发 比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于网站架构从前到后都是一种考验. 2.超卖 任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难题. 二.如何解决? 首先,产品解决方案我们就不予讨论了.我们只讨论技术解决方案 1.前端 面对高并发的

关于秒杀和超卖的性能问题

一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其中[抢订单]这个环节是最考验业务提供方的抗压能力的. 抢订单环节一般会带来2个问题: 1.高并发 比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于网站架构从前到后都是一种考验. 2.超卖 任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难题. 二.如何解决? 首先,产品解决方案我们就不予讨论了.我们只讨论技术解决方案 1.前端 面对高并发的

如何解决秒杀的性能问题和超卖的讨论

如何解决秒杀的性能问题和超卖的讨论 最近业务试水电商,接了一个秒杀的活.之前经常看到淘宝的同行们讨论秒杀,讨论电商,这次终于轮到我们自己理论结合实际一次了. ps:进入正文前先说一点个人感受,之前看淘宝的ppt感觉都懂了,等到自己出解决方案的时候发现还是有很多想不到的地方其实都没懂,再次验证了“细节是魔鬼”的理论.并且一个人的能力有限,只有大家一起讨论才能想的更周全,更细致.好了,闲话少说,下面进入正文. 一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其

秒杀与超卖的 性能解决之路

一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其中[抢订单] 这个环节是最考验业务提供方的抗压能力的. 抢订单环节一般会带来2个问题: 1.高并发 比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于 网站架构从前到后都是一种考验. 2.超卖 任何商品都会有数量上限,如何避免成功下订单买到商品的人数不 超过商品数量的上限,这是每个抢购活动都要面临的难题. 二.如何解决? 首先,产品解决方案我们就不予讨论了.我们只讨论技术解决方案 1.前端 面对高