thinkphp6 redis秒杀商品代码

//在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);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风之梦丽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值