Skip to content Skip to sidebar Skip to footer

1.开发环境,nginx+mysql+Linux+php(thinkphp5)+redis。通过jmeter模拟并发场景。
模拟场景:500人同一时间抢购30部手机,通过PHP实现乐观锁。

public function sale_order(){
        $user_id = mt_rand(1,100000);
        $goods_info = Db::name('goods')->where('id',1)->find();
        if($goods_info['goods_num'] <= 0){
            return '商品已售罄';
        }
        $user_info = Db::name('wallet')->where('user_id',$user_id)->find();
        if(empty($user_info)){
            return '用户信息不存在';
        }
        if($user_info['money']<$goods_info['flash_sale_price']){
            return '秒杀失败,余额不足';
        }
        $order_num = $this->get_order_num();
        $order_info = [
            'order_num'     => $order_num,
            'user_id'       => $user_id,
            'goods_id'      => $goods_info['id'],
            'num'           => 1
        ];
        $goods_data = [
            'goods_num'     => $goods_info['goods_num'] -1,
            'version'       => $goods_info['version'] + 1,
        ];
        $goods_where_data = [
            'id'            => $goods_info['id'],
            'version'       => $goods_info['version']
        ];
        $user_banlance = round(($user_info['money'] - $goods_info['flash_sale_price']),2);
        Db::startTrans();
        try{
            $res = Db::name('goods')->where($goods_where_data)
                ->update($goods_data);
            if($res != 1){
                Exception('减库存失败',0);
            }
            Db::name('goods_order')->insert($order_info);
            Db::name('wallet')->where('user_id',$user_info['id'])
                ->update(['money'=>$user_banlance]);
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            $log_data = [
                'log'   =>   $e->getMessage(),
            ];
            Db::name('log')->insert($log_data);
            return '下单失败';
        }
        return '下单成功';
    }

2.运行结果如下:

从上图可以看到,在500并发的情况下,商品没有超卖,但是也没有卖光。因此需要在此基础上模拟用户重复刷新的动作。

3.这次用户下单失败后还会继续重复下单6次。

从上图可以看到,通过乐观锁,成功避免了超卖问题,类似的操作也可以通过PHP+Redis分布式锁实现。

Leave a comment