加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ActiveGoodsLogicResult.php 7.95 KB
一键复制 编辑 原始数据 按行查看 历史
<?php
class ActiveGoodsLogicResult
{
private $redis;
private $stockPrefix;
private $userPrefix;
private $statusPrefix;
private $lockPrefix;
/**
* 构造函数
*
* @param string $stockPrefix Redis库存键前缀
* @param string $userPrefix Redis用户抢购键前缀
* @param string $statusPrefix Redis活动状态键前缀
* @param string $lockPrefix Redis锁键前缀
*/
public function __construct($stockPrefix = 'active_goods_stock_', $userPrefix = 'user_purchase_', $statusPrefix = 'active_status_', $lockPrefix = 'lock_user_')
{
// 初始化 Redis 连接
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
// 设置 Redis 键前缀
$this->stockPrefix = $stockPrefix;
$this->userPrefix = $userPrefix;
$this->statusPrefix = $statusPrefix;
$this->lockPrefix = $lockPrefix;
}
/**
* 初始化活动商品库存
*
* @param int $activeGoodsId 活动商品ID
* @param int $stock 初始库存数量
* @return array 返回操作结果
*/
public function initStock($activeGoodsId, $stock)
{
$stockKey = $this->stockPrefix . $activeGoodsId;
$statusKey = $this->statusPrefix . $activeGoodsId;
$this->redis->set($stockKey, $stock);
$this->redis->set($statusKey, 1); // 活动状态设置为进行中
return ['status' => 200, 'message' => '库存初始化成功'];
}
/**
* 提前结束活动
*
* @param int $activeGoodsId 活动商品ID
* @return array 返回操作结果
*/
public function endActivity($activeGoodsId)
{
$statusKey = $this->statusPrefix . $activeGoodsId;
$this->redis->set($statusKey, 0); // 活动状态设置为结束
return ['status' => 200, 'message' => '活动已结束'];
}
/**
* 秒杀抢购操作
*
* @param int $userId 用户ID
* @param int $activeGoodsId 活动商品ID
* @param int $maxAttempts 用户最大抢购次数
* @return array 返回抢购结果
*/
public function seckill($userId, $activeGoodsId, $maxAttempts = 1)
{
$stockKey = $this->stockPrefix . $activeGoodsId;
$userKey = $this->userPrefix . $userId . '_' . $activeGoodsId;
$statusKey = $this->statusPrefix . $activeGoodsId;
$lockKey = $this->lockPrefix . $userId . '_' . $activeGoodsId;
// 获取锁
$lock = $this->acquireLock($lockKey, 5);
if (!$lock) {
return ['status' => 500, 'message' => '请求过于频繁,请稍后再试'];
}
try {
// 检查活动是否已结束
$status = $this->redis->get($statusKey);
if ($status == 0) {
return ['status' => 500, 'message' => '活动已结束'];
}
// 获取当前用户已抢购次数
$attempts = $this->redis->get($userKey);
if ($attempts && $attempts >= $maxAttempts) {
return ['status' => 500, 'message' => '您已经达到最大抢购次数'];
}
// 执行Lua脚本来检查并扣减库存
$luaScript = "
local stockKey = KEYS[1]
local userKey = KEYS[2]
local statusKey = KEYS[3]
local maxAttempts = tonumber(ARGV[1])
local attempts = redis.call('get', userKey)
local status = redis.call('get', statusKey)
if status == '0' then
return -2
end
if attempts and tonumber(attempts) >= maxAttempts then
return -1
end
local stock = tonumber(redis.call('get', stockKey))
if stock and stock > 0 then
redis.call('decr', stockKey)
redis.call('incr', userKey)
return 1
else
return 0
end
";
$result = $this->redis->eval($luaScript, [$stockKey, $userKey, $statusKey], 3, $maxAttempts);
if ($result == 1) {
return ['status' => 200, 'message' => '抢购成功'];
} elseif ($result == -1) {
return ['status' => 500, 'message' => '您已经达到最大抢购次数'];
} elseif ($result == -2) {
return ['status' => 500, 'message' => '活动已结束'];
} else {
return ['status' => 500, 'message' => '库存不足,抢购失败'];
}
} finally {
// 释放锁
$this->releaseLock($lockKey);
}
}
/**
* 获取分布式锁
*
* @param string $lockKey 锁的键
* @param int $expire 锁的过期时间(秒)
* @return bool 是否获取成功
*/
private function acquireLock($lockKey, $expire)
{
$isLocked = $this->redis->set($lockKey, 1, ['nx', 'ex' => $expire]);
return $isLocked ? true : false;
}
/**
* 释放分布式锁
*
* @param string $lockKey 锁的键
*/
private function releaseLock($lockKey)
{
$this->redis->del($lockKey);
}
/**
* 取消订单还原库存
*
* @param int $userId 用户ID
* @param int $activeGoodsId 活动商品ID
* @return array 返回还原结果
*/
public function restoreStock($userId, $activeGoodsId)
{
$stockKey = $this->stockPrefix . $activeGoodsId;
$userKey = $this->userPrefix . $userId . '_' . $activeGoodsId;
// 执行Lua脚本来还原库存并删除用户抢购记录
$luaScript = "
local stockKey = KEYS[1]
local userKey = KEYS[2]
local attempts = redis.call('get', userKey)
if attempts and tonumber(attempts) > 0 then
redis.call('decr', userKey)
redis.call('incr', stockKey)
return 1
else
return 0
end
";
$result = $this->redis->eval($luaScript, [$stockKey, $userKey], 2);
if ($result) {
return ['status' => 200, 'message' => '库存已还原'];
} else {
return ['status' => 500, 'message' => '无有效的取消操作'];
}
}
/**
* 商家追加库存
*
* @param int $activeGoodsId 活动商品ID
* @param int $additionalStock 追加的库存数量
* @return array 返回追加结果
*/
public function addStock($activeGoodsId, $additionalStock)
{
$stockKey = $this->stockPrefix . $activeGoodsId;
$this->redis->incrby($stockKey, $additionalStock);
return ['status' => 200, 'message' => '库存追加成功'];
}
/**
* 直接扣除库存
*
* @param int $activeGoodsId 活动商品ID
* @param int $deductStock 要扣除的库存数量
* @return array 返回扣除结果
*/
public function deductStock($activeGoodsId, $deductStock)
{
$stockKey = $this->stockPrefix . $activeGoodsId;
$this->redis->decrby($stockKey, $deductStock);
return ['status' => 200, 'message' => '库存扣除成功'];
}
}
// 示例用法:
$logic = new ActiveGoodsLogicResult();
// 初始化库存
echo json_encode($logic->initStock($activeGoodsId, 100));
// 用户抢购,最大抢购次数为3
echo json_encode($logic->seckill($userId, $activeGoodsId, 3));
// 提前结束活动
echo json_encode($logic->endActivity($activeGoodsId));
// 取消订单还原库存
echo json_encode($logic->restoreStock($userId, $activeGoodsId));
// 商家追加库存
echo json_encode($logic->addStock($activeGoodsId, 50));
// 直接扣除库存
echo json_encode($logic->deductStock($activeGoodsId, 20));
?>
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化