php限时抢购实现思路
PHP限时抢购实现思路
数据库设计
创建商品表时需包含抢购相关字段,例如:start_time(开始时间)、end_time(结束时间)、quantity(总库存)、sold(已售数量)。核心字段结构示例:
CREATE TABLE `flash_sale` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item_name` varchar(255) NOT NULL,
`price` decimal(10,2) NOT NULL,
`quantity` int(11) NOT NULL COMMENT '总库存',
`sold` int(11) DEFAULT 0 COMMENT '已售',
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
时间验证逻辑
在抢购接口入口处校验当前时间是否在活动期内:

$now = time();
if ($now < strtotime($item['start_time']) || $now > strtotime($item['end_time'])) {
die('活动未开始或已结束');
}
库存原子操作
使用MySQL事务+乐观锁保证库存操作的原子性:
$pdo->beginTransaction();
try {
// 查询库存时加锁
$stmt = $pdo->prepare("SELECT quantity, sold FROM flash_sale WHERE id = ? FOR UPDATE");
$stmt->execute([$item_id]);
$stock = $stmt->fetch();
if ($stock['quantity'] <= $stock['sold']) {
throw new Exception('库存不足');
}
// 更新库存
$update = $pdo->prepare("UPDATE flash_sale SET sold = sold + 1 WHERE id = ?");
$update->execute([$item_id]);
// 生成订单等其他业务逻辑
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
die($e->getMessage());
}
缓存预热与限流
使用Redis预处理和限制请求:

- 活动开始前预热库存到Redis:
$redis->set('fs_stock_' . $item_id, $total_quantity); - 使用计数器限流:
$key = 'fs_user_' . $user_id; if ($redis->incr($key) > 1) { die('请勿重复提交'); } $redis->expire($key, 10); // 10秒内禁止重复提交
消息队列异步处理
高并发时用队列处理核心业务:
// 抢购请求入队
$rabbitMQ->publish([
'user_id' => $user_id,
'item_id' => $item_id
], 'flash_sale_queue');
// 消费者处理订单
$callback = function ($msg) {
// 实际的库存扣减和订单创建逻辑
};
$channel->basic_consume('flash_sale_queue', '', false, true, false, false, $callback);
静态化与CDN
商品详情页静态化处理,通过Nginx直接返回静态HTML,减少PHP解析压力。配置示例:
location /flashsale/item-123 {
try_files /static/flashsale/item-123.html @php_backend;
}
注意事项
- 前端需添加倒计时和状态提示
- 实施IP限流防止机器人请求
- 记录详细日志用于对账
- 压力测试需模拟峰值流量的3倍以上






