当前位置:首页 > 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
分享给朋友:

相关文章

vue ssr实现思路

vue ssr实现思路

Vue SSR 实现思路 Vue SSR(Server-Side Rendering)的核心目标是在服务端生成完整的 HTML 页面,提升首屏加载速度和 SEO 友好性。以下是关键实现思路: 基础架…

php验证码实现

php验证码实现

验证码实现方法 在PHP中实现验证码功能通常涉及生成随机字符串或数字,将其转换为图像,并通过会话(Session)进行验证。以下是几种常见的实现方式: 使用GD库生成图像验证码 GD库是PHP内置的…

php实现排序

php实现排序

PHP 数组排序方法 PHP 提供了多种内置函数用于数组排序,适用于不同的排序需求。以下是常见的排序方法: 按值升序排序 sort() 函数对数组按值升序排序,重置键名(索引数组适用): $num…

php 实现文件下载

php 实现文件下载

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

php实现跳转

php实现跳转

PHP 实现页面跳转的方法 在 PHP 中实现页面跳转有多种方式,以下是常见的几种方法及其适用场景: 使用 header() 函数 通过 header() 函数发送 HTTP 头部信息实现跳转。注意…

php实现即时通讯

php实现即时通讯

PHP 实现即时通讯的方案 即时通讯(IM)可以通过多种方式实现,PHP 作为服务器端语言,通常需要结合前端技术(如 WebSocket、AJAX)或第三方服务来实现实时通信。以下是几种常见的实现方式…