假设已安装并配置好ThinkPHP 6及Redis扩展。
1. 安装依赖
确保已安装topthink/think-queue
(用于消息队列)和topthink/framework
(ThinkPHP 6核心包):
composer require topthink/think-queue topthink/framework
2. 配置Redis
在config/cache.php
中配置Redis作为默认缓存驱动:
return [
// ...
'default' => 'redis',
'stores' => [
'redis' => [
'type' => '\think\cache\driver\Redis',
'host' => '127.0.0.1',
'port' => 6379,
// ... 其他配置项如密码、数据库索引等
],
],
];
3. 创建模型、控制器、中间件
app/model/Product.php
(商品模型)
namespace app\model;
use think\Model;
class Product extends Model
{
protected $table = 'products';
public static function decreaseStock(int $productId, int $quantity)
{
self::where('id', $productId)->dec('stock', $quantity)->update();
}
}
app/controller/SeckillController.php
(秒杀控制器)
namespace app\controller;
use app\model\Product;
use think\Request;
use think\Queue;
use think\response\Json;
class SeckillController extends BaseController
{
public function seckill(Request $request)
{
$productId = $request->param('product_id');
$userId = $request->param('user_id');
if (!self::tryLock($productId)) {
return Json::create(['status' => 'failed', 'message' => '系统繁忙,请稍后重试']);
}
try {
$success = self::handleSeckill($productId, $userId);
if ($success) {
return Json::create(['status' => 'success', 'message' => '秒杀成功']);
} else {
return Json::create(['status' => 'failed', 'message' => '秒杀失败,请稍后重试']);
}
} finally {
self::unlock($productId);
}
}
private function tryLock(int $productId): bool
{
// 使用Redis实现分布式锁,这里简化为使用setnx模拟
$redis = \think\facade\Cache::store('redis')->handler();
$lockKey = 'seckill_lock_' . $productId;
return $redis->setnx($lockKey, time());
}
private function unlock(int $productId): void
{
// 使用Redis释放分布式锁,这里简化为删除键模拟
$redis = \think\facade\Cache::store('redis')->handler();
$lockKey = 'seckill_lock_' . $productId;
$redis->del($lockKey);
}
private function handleSeckill(int $productId, int $userId): bool
{
// 假设已从缓存中获取到商品剩余库存
$remainingStock = self::getRemainingStockFromCache($productId);
if ($remainingStock <= 0) {
return false;
}
// 减库存、创建订单等业务逻辑
Product::decreaseStock($productId, 1);
// 发送队列任务,如发送通知、更新用户状态等
Queue::push(new SeckillSuccessJob([
'product_id' => $productId,
'user_id' => $userId,
]));
return true;
}
private function getRemainingStockFromCache(int $productId): int
{
// 省略从缓存中获取剩余库存的逻辑,实际应用中应从Redis中获取
return 10; // 假设剩余库存为10
}
}
4. 创建消息队列任务
app/jobs/SeckillSuccessJob.php
(秒杀成功后的异步任务)
namespace app\jobs;
use think\queue\Job;
use think\facade\Log;
class SeckillSuccessJob
{
public function __construct(array $data)
{
$this->data = $data;
}
public function handle(Job $job, $data)
{
// 这里实现异步任务逻辑,如发送通知、更新用户状态等
// 完成任务后删除
$job->delete();
}
public function failed(\Throwable $exception)
{
Log::error('SeckillSuccessJob failed: ' . $exception->getMessage());
}
}
5. 配置并启动消息队列
在
config/queue.php
中配置消息队列驱动(如rabbitmq
、redis
等)。然后启动队列监听器:php think queue:listen --queue=seckill_queue