您所在的位置:首页 - PHP - 正文PHP

thinkphp6+redis 秒杀商品demo

萧何-Vincent 萧何-Vincent 2022-11-25 【PHP】 1674人已围观

//在tp6中think\cache\Driver代码中添加返回缓存对象方法:
/**
     * @desc 获取缓存操作对象
     * @return object
     */
    public function getHandler(){
    return $this->handler;
    }
//在项目config/cache.php文件中添加redis配置信息
'redis'=>[
'type'=> 'redis',
'host'=> '127.0.0.1',
'port'=> '6379',
'password' => '123456789',
'select'   => '0',
// 全局缓存有效期(0为永久有效)
'expire'   => 0,
// 缓存前缀
'prefix'   => '',
'timeout'  => 0,
],
//添加随机goods信息,及将goods库存添加如redis中
public function addGoods(){
    $redis = Cache::store('redis')->getHandler();
    $data = [];
    for($i = 1;$i < 101;$i++){
    $store = intval(rand(1000,9999));
    $data[] = [
    'id'=> $i,
    'goods_name'=>$this->getChar(5),
    'goods_store'=> $store,
    'goods_price'=> round(rand(1000,9999)/100,2),
    ];
    $key = "goods_stock_".$i;
    $redis->set($key, $store);
    }
    $ids = Db::name('test_goods')->insertAll($data);
    echo $ids;
}
//php随机生成汉字 $num为生成汉字的数量
public function getChar($num){
$b = '';
for ($i=0; $i<$num; $i++) {
$a = chr(mt_rand(0xB0,0xD0)).chr(mt_rand(0xA1, 0xF0));
$b .= iconv('GB2312', 'UTF-8', $a);
}
return $b;
}
//循环随机买家购买订单
public function doOrder(){
$user_list = Db::name('test_user')->orderRaw('rand()')->select();
foreach($user_list as $k=>$v){
$result = $this->buyOrder($v['id'], 97);
if($result['status'] == 0){
echo $result['message'].'<br/>';
}else{
echo '成功下单:'.$result['message'].'<br/>';
}
}
}
/**
     * 下单 redis乐观锁,是用一个watch,就是去加一个监视器。
     * @return \think\Response
     */
public function buyOrder($user_id, $goods_id)
    {
    $redis = Cache::store('redis')->getHandler();
//goods库存key
        $goods_key = 'goods_stock_'.$goods_id;
        //监听对应的key
        $redis->watch($goods_key);
        //获取goods库存
        $goods_store = $redis->get($goods_key);
        
        //抢购成功买家集合key
        $orderUserKey = 'goodsOrderUserSet';
        //判断买家是否在集合中,在则说明已购买。
        $status = $redis->sismember($orderUserKey, $user_id);
        if($status){
        return ['status'=>0, 'message'=>$user_id.'已抢过订单'];
        }
        //抢购成功买家队列key
        $buyUserList = 'goodsBuyUserList';
        if($goods_store > 0){
        $redis->multi();//开启事务
        $redis->decr($goods_key);//减少库存
        $redis->sadd($orderUserKey, $user_id);//将买家id添加到抢购成功买家集合中
        
        $res = $redis->exec(); //执行所有事务块内的命令
        if($res){
        //将goods和买家id放入队列中,再之后继续循环生成订单操作。这边也可以将信息存入消息队列。
        $redis->lPush($buyUserList, $goods_id.'_'.$user_id);
        return ['status'=>1, 'message'=> $user_id.'下单成功'];
        }else{
        return ['status'=>0, 'message'=> $user_id.'商品库存执行失败'];
        }
        }else{
        return ['status'=>0, 'message'=> $user_id.'商品库存不足,请下次再购买'];
        }
    }
//秒杀循环生成订单
    public function afterOrder(){
    $begin_time = time();
    echo '开始时间:'.date('Y-m-d H:i:s',$begin_time).'<br/>';
    $buyUserList = 'goodsBuyUserList';
    $redis = Cache::store('redis')->getHandler();
    $len = $redis->llen($buyUserList);
    while($len > 0){
    $order_info = $redis->rPop($buyUserList);
    if($order_info){
    $orders = explode('_', $order_info);
    $goods_id = $orders[0];
    $user_id = $orders[1];
    if(!empty($goods_id) && !empty($user_id) && intval($goods_id) && intval($user_id)){
    // 启动事务
    Db::startTrans();
    try {
    $user_obj = Db::name('test_user')->where('id', $user_id)->find();
    $goods_obj = Db::name('test_goods')->where('id', $goods_id)->find();
    //更新商品库存信息
    $goods_result = Db::name('test_goods')->where('id', $goods_id)->dec('goods_store')->update();
    //添加订单信息
    $order_data = [];
    $order_data = [
    'order_no' => date('YmdHis').rand(100000,999999),
    'buyer_id'=> $user_id,
    'buyer_name'=> $user_obj['true_name'],
    'goods_id'=> $goods_id,
    'goods_num'=> 1,
    'goods_price'=> $goods_obj['goods_price'],
    'add_time'=> date('Y-m-d H:i:s'),
    ];
    $order_id = Db::name('test_order')->insertGetId($order_data);
    // 提交事务
    Db::commit();
    
    error_log($user_id.'=='.$goods_id.'生成订单成功,订单id:'.$order_id.',订单号为:'.$order_data['order_no']."\r\n", 3, 'order_'.date('Ymd').'.log');
    } catch (\Exception $e) {
    // 回滚事务
    Db::rollback();
    error_log($user_id.'=='.$goods_id.'生成订单失败'."\r\n", 3, 'order_'.date('Ymd').'.log');
    }
    }
    }
    $len = $redis->llen($buyUserList);
    }
    $end_time = time();
    echo '结束时间:'.date('Y-m-d H:i:s',$end_time).'<br/>';
    echo '总操作时间:'.($end_time-$begin_time);
    }









原文地址:https://blog.csdn.net/fld4123/article/details/126891098

文章评论 (暂无评论,1674人围观)

我的名片

网名:Vincent

职业:IT

现居:SZ

Email:53126692@qq.com

站长寄语:技术分享,支持原创!

站点信息

  • 文章总数:65
  • 页面总数:1
  • 分类总数:5
  • 标签总数:12
  • 评论总数:24
  • 浏览总数:82970
取消
微信二维码
支付宝二维码

目录[+]