php限时抢购实现思路
限时抢购功能概述
限时抢购是电商常见的高并发场景,需解决库存超卖、系统性能、数据一致性等问题。PHP实现需结合数据库、缓存、队列等技术。
数据库设计
商品表需包含抢购相关字段:
CREATE TABLE `seckill_goods` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`stock` int(11) NOT NULL COMMENT '总库存',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime NOT NULL COMMENT '结束时间',
`version` int(11) DEFAULT '0' COMMENT '乐观锁版本号',
PRIMARY KEY (`id`)
);
订单表记录抢购结果:

CREATE TABLE `seckill_orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`goods_id` int(11) NOT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`)
);
防止超卖方案
悲观锁方案
通过SELECT...FOR UPDATE锁定记录,适合低并发场景:
$pdo->beginTransaction();
$stmt = $pdo->prepare("SELECT stock FROM seckill_goods WHERE id=? FOR UPDATE");
$stmt->execute([$goods_id]);
$stock = $stmt->fetchColumn();
if ($stock > 0) {
$pdo->prepare("UPDATE seckill_goods SET stock=stock-1 WHERE id=?")->execute([$goods_id]);
// 创建订单...
$pdo->commit();
} else {
$pdo->rollBack();
}
乐观锁方案
通过版本号控制并发,适合高并发场景:

$version = $pdo->query("SELECT version FROM seckill_goods WHERE id=$goods_id")->fetchColumn();
$affected = $pdo->exec("UPDATE seckill_goods SET stock=stock-1, version=version+1
WHERE id=$goods_id AND version=$version");
if ($affected > 0) {
// 创建订单...
}
性能优化策略
Redis预减库存
活动开始前将库存加载到Redis,通过原子操作减少数据库压力:
$redis = new Redis();
$redis->decr('seckill:goods:' . $goods_id);
if ($redis->get('seckill:goods:' . $goods_id) >= 0) {
// 进入下单队列
}
消息队列削峰
使用RabbitMQ或Redis List缓冲请求:
// 生产者
$redis->lPush('seckill:queue', json_encode(['user_id'=>$userId, 'goods_id'=>$goodsId]));
// 消费者
while ($data = $redis->rPop('seckill:queue')) {
$orderData = json_decode($data, true);
// 处理下单逻辑
}
其他注意事项
- 采用Nginx+Lua实现限流(如令牌桶算法)
- 前端增加倒计时和按钮防重复点击
- 使用分布式锁(Redisson)防止集群环境下的并发问题
- 活动结束后关闭服务器抢购入口
完整流程示例
- 用户请求抢购接口
- 检查活动时间有效性
- Redis预减库存并返回剩余量
- 消息队列接收请求
- 后台进程处理真实下单
- 返回抢购结果异步通知
高并发场景建议结合Swoole等常驻内存方案提升性能,数据库采用分库分表策略。






