当前位置:首页 > PHP

php 抢购实现思路

2026-02-15 07:50:19PHP

数据库设计

使用InnoDB引擎确保事务支持,创建商品表包含库存字段(如stock),订单表记录抢购成功数据。关键字段需添加索引,如商品ID和用户ID组合索引。

CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `stock` int(11) NOT NULL COMMENT '库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_product_user` (`product_id`,`user_id`)
) ENGINE=InnoDB;

悲观锁实现

在事务内使用SELECT FOR UPDATE锁定商品记录,确保库存检查与扣减的原子性。需注意事务粒度控制,避免长时间锁表。

$pdo->beginTransaction();
try {
    $stmt = $pdo->prepare('SELECT stock FROM product WHERE id = ? FOR UPDATE');
    $stmt->execute([$productId]);
    $stock = $stmt->fetchColumn();

    if ($stock > 0) {
        $pdo->prepare('UPDATE product SET stock = stock - 1 WHERE id = ?')->execute([$productId]);
        $pdo->prepare('INSERT INTO order (product_id, user_id) VALUES (?, ?)')->execute([$productId, $userId]);
    }
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
}

乐观锁实现

通过版本号或时间戳字段实现无锁并发控制。更新时校验版本号,冲突时自动重试或失败。适合并发量中等场景。

php 抢购实现思路

$version = $pdo->query("SELECT version FROM product WHERE id = $productId")->fetchColumn();
$affected = $pdo->exec("UPDATE product SET stock = stock - 1, version = version + 1 
                        WHERE id = $productId AND version = $version");

if ($affected === 0) {
    throw new Exception('抢购失败');
}

缓存预减库存

采用Redis原子操作预减库存,Lua脚本保证操作原子性。实际库存不足时快速返回,减轻数据库压力。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$lua = "
local stock = tonumber(redis.call('get', KEYS[1]))
if stock > 0 then
    redis.call('decr', KEYS[1])
    return 1
end
return 0
";

$res = $redis->eval($lua, ['product_stock_' . $productId], 1);
if ($res === 0) {
    die('已售罄');
}

队列削峰

使用RabbitMQ或Kafka将请求异步化,消费者顺序处理订单。结合令牌桶算法控制处理速率,实现流量整形。

php 抢购实现思路

$channel->queue_declare('seckill', false, true, false, false);
$channel->basic_publish(
    new AMQPMessage(json_encode(['product_id' => $productId, 'user_id' => $userId]), 
    '', 
    'seckill'
);

限流措施

Nginx层实现IP限流,PHP应用层使用Redis计数器限制用户频率。滑动窗口算法统计单位时间请求量。

$key = 'user_limit_' . $userId;
$count = $redis->incr($key);
if ($count === 1) {
    $redis->expire($key, 10);
}
if ($count > 5) {
    die('操作过于频繁');
}

数据一致性

通过定时任务核对Redis与数据库库存差异,引入分布式锁处理超卖。采用本地消息表实现最终一致性。

// 核对脚本示例
$dbStock = $pdo->query("SELECT stock FROM product WHERE id = 1")->fetchColumn();
$redisStock = $redis->get('product_stock_1');
if ($dbStock != $redisStock) {
    // 触发补偿逻辑
}

前端优化

静态资源CDN加速,按钮提交后禁用防止重复点击。倒计时结束前预加载接口,减少网络延迟影响。

document.getElementById('btn').addEventListener('click', function() {
    this.disabled = true;
    fetch('/seckill', {method: 'POST'});
});

标签: 思路php
分享给朋友:

相关文章

php长连接实现

php长连接实现

PHP 长连接实现方法 长连接(Keep-Alive)允许客户端与服务器在一次TCP连接中发送和接收多个HTTP请求/响应,减少重复建立连接的开销。以下是PHP中实现长连接的几种方式: 配置HTTP…

php 实现文件下载

php 实现文件下载

实现文件下载的基本方法 使用 PHP 实现文件下载的核心是通过设置 HTTP 头部信息,强制浏览器将文件作为附件下载而非直接显示。以下是一个基础实现示例: $file_path = '/path/t…

php 实现下载

php 实现下载

PHP 实现文件下载的方法 使用 PHP 实现文件下载可以通过设置 HTTP 头信息,强制浏览器将文件作为附件下载而非直接打开。 基本下载实现 $file_path = 'path/to/your/…

php实现推送消息推送消息

php实现推送消息推送消息

PHP 实现消息推送的方法 使用 WebSocket 实现实时推送 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,适合实现实时消息推送。 安装 Ratchet 库(WebSo…

php登陆功能实现

php登陆功能实现

实现PHP登录功能 数据库准备 创建一个用户表存储登录信息,基本字段包括用户名、密码(需加密)等: CREATE TABLE users ( id INT AUTO_INCREMENT PR…

php 实现评论

php 实现评论

实现 PHP 评论功能 数据库设计 创建数据库表存储评论数据,通常包含以下字段: id:评论唯一标识 user_id:用户ID content:评论内容 created_at:评论时间 parent…