轉載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處理一般的搶購(秒殺).