PHP处理库存超卖的几种处理方法

2023-12-14 14:10:56 浏览数 (1)

专栏持续更新中:MySQL详解

第一种方法:使用mysql数据库的锁机制。在事务中使用 for update 语句,在事务处理完成之后释放这一条数据。

代码使用tp5的框架:

代码语言:javascript复制
public function mysqlLock(){
    $goods_id = 26545;
    $sku_id = 26545;
    $price = 300;
    $user = '';
    StoreOrderModel::startTrans();
    $nums = StoreOrderModel::where(['id'=>1])->field('number')->lock(true)->find();
    $nums = $nums['number'];
    if($nums > 0){
        $item['goods_id'] = $goods_id;
        $item['sku_id'] = $sku_id;
        $item['number'] = $nums;
        $item['price'] = $price;
        $item['user'] = $user;
        $id = StoreModel::insertGetId($item);
        if($id){
            StoreOrderModel::where(['id'=>1])->setDec('number');
            StoreOrderModel::commit();
        }else{
            StoreOrderModel::rollback();
        }
    }else{
        echo "没有库存了";
    }
}

第二种方法:redis 事务。

代码语言:javascript复制
public function start_reids_tran(){
    $goods_id = 26545;
    $sku_id = 26545;
    //$number = 1;
    $price = 300;
    $user = '';
    $redis = ResRedisModel::getinstance();
    $redis->watch('store');
    $nums = intval($redis->get('store'));
    if($nums > 0){
        $item['goods_id'] = $goods_id;
        $item['sku_id'] = $sku_id;
        $item['number'] = $nums;
        $item['price'] = $price;
        $item['user'] = $user;
        $redis->lPush('success', json_encode($item));
        $redis->multi();
        $redis->decr('store');
        $replies = $redis->exec(); // 执行以上 redis 事务
        if(!$replies){
            echo "订单 {$nums} 回滚".PHP_EOL;
        }
        $redis->unwatch();
        echo "抢购成功!".PHP_EOL;
    }else{
        echo "没有库存了";
    }
}

第三种方法:redis 队列,预先把库存信息存入队列当中,抢购时判断队列的数量,然后出队。队列为空时库存为0。

代码语言:javascript复制
public function  eq_start(){

    $redis = ResRedisModel::getinstance();
    $nums = $redis->lSize('store');
    $goods_id = 26545;
    $sku_id = 26545;
    $number = 1;
    $price = 300;
    $user = '';

    if($nums > 0){
        $user = $redis->rPop('store');
        if($user){
            $item['goods_id'] = $goods_id;
            $item['sku_id'] = $sku_id;
            $item['number'] = $number;
            $item['price'] = $price;
            $item['user'] = $user;
            StoreModel::insertGetId($item);
            echo '抢购成功!';
        }else{
            echo '抢购失败!';
        }
    }else{
        echo '抢购失败!';
    }
}

第四种:文件排他锁方式

代码语言:javascript复制
public function file_star(){

    $fp = fopen('D:/phpStudy/PHPTutorial/www/public/lock.txt', "r");

    if(flock($fp, LOCK_EX)) { //排他型锁定 阻塞模式 , flock($fp,LOCK_EX | LOCK_NB) 非阻塞模式

        $nums = StoreOrderModel::where(['id'=>1])->field('number')->find();
        $nums = $nums['number'];

        if($nums > 0){
            $goods_id = 26545;
            $sku_id = 26545;
            $number = 1;
            $price = 300;
            $user = '213';
            $item['goods_id'] = $goods_id;
            $item['sku_id'] = $sku_id;
            $item['number'] = $number;
            $item['price'] = $price;
            $item['user'] = $user;
            StoreModel::insertGetId($item);
            StoreOrderModel::where(['id'=>1])->setDec('number');
            flock($fp, LOCK_UN); //释放锁定
            echo '抢购成功!';
        }else{
            echo '没有库存了!';
        }
    }else{
        echo '抢购失败!';
    }
    fclose($fp);
}

0 人点赞