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

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