TP5使用Redis处理一般的抢购(秒杀)

转载tp框架文档,知识学习
文章转载地址在下方注明,本文章只做记录。

1、首先在TP5中创建抢购活动所需要的Redis类库文件,代码如下:
namespace app\base\service;
use mikkle\tp_redis\RedisHashInfoBase;
use think\Exception;
/**
 * 
*/
class ScheduleDetail extends RedisHashInfoBase
{

	protected $table = "gopar_schedule_detail";//数据表的
	protected $pk = "id";

	public function _initialize(){
		//判断数据存在,并设置检查周期10分钟
		if (!$this->checkLock("dataExists") && !$this->checkTableDataExists()) {
			throw new Exception("相关产品数据不存在");
		}else{
			//设置检查锁10分钟
			$this->setLock("dataExists",600);
		}

		//如果数据不存在,初始化读取数据
		if(!$this->checkExists()){
            $this->initTableData();
		}
	}

	public function getScheduleCenter()
	{
		return Schedule::instance($this->getInfoFieldValue("schedule_id"));
	}

	public function _destruct()
	{
		//设置15天自动回收Redis
	    $this->setExpire(int);
	    $this->getScheduleCenter()->getInfoFieldValue('end_time')+3600*24*15);
	}
}
在服务层或者控制器处理抢购逻辑
public function index($data=["user_id"=>1,"ticket_detail_id"=>1,"buy_num"=>1])
{
	try{
		//监测数据存在
		if(!$this->checkArrayValueEmpty($data,['user_id','ticket_detail_id','buy_num'])){
			throw new Exception($this->error);
			
		}
		$user_id = $data['user_id'];//用户ID
		$ticket_detail_id = $data['ticket_detail_id'];//产品ID
		$buy_num = $data['buy_num'];//购买数量
		$infoCenter = ScheduleDetail::instance($ticket_detail_id);

		$scheduleDetailInfo = $infoCenter->getInfoList();

		//修改数据库后,需要运行initTableData()方法重新舒适化,推荐写到Hook里
		//$infoCenter->initTableData();
		if($infoCenter->getInfoFieldValue('hot_schedule')){
			//热门抢购随机过滤
			if(in_array(rand(100,200)%11,[1,3,5,7,9])){
				throw new Exception("抢票人数众多,你被挤出抢购队伍,还有余票,请重新再抢");
			}

		}

		//这里判断购买数量和销售日期,不符合就throw new Exception
		if (!true) {
			throw new Exception("这里写不符合原因");
		}

		if(((int)$infoCenter->getInfoFieldValue("{$user_id}_num")+$buy_num)>$scheduleDetailInfo["limit_num"]){
			throw new Exception("你超过最大购买数量");
		}

		if($infoCenter->setInfoFieldIncre('pay_num',$buy_num)>$scheduleDetailInfo['limit_num']){
			$infoCenter->setInfoFieldIncre('pay_num',-$buy_num);
			throw new Exception("对不起,票已经卖光了!");
		}

		//这里写主逻辑,启用事务功能创建订单
		//事务参见下方源码
		//升级已销售数量
		$infoCenter->updateTableData(['pay_num']);
		//在这里推荐埋钩子,处理订单完成后的后续事情
		//返回结果

	}catch(Exception $e){
		Log::error($e->getMessage());
		return ShowCode::jsonCodeWithoutData(1008,$e->getMessage())
	}
}
在处理逻辑中,可以使用随机去除了一部分的购买请求,以保证抢购活动平稳完成,当然也可以同时在前端请求中示例类似方法过滤。
可以参照定时队列判断订单是否处理完成,校准剩余库存。

参考文章:tp5使用Redis处理一般的抢购(秒杀).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章