转载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处理一般的抢购(秒杀).