当前位置:首页 > 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();
}

乐观锁实现

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

$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将请求异步化,消费者顺序处理订单。结合令牌桶算法控制处理速率,实现流量整形。

$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加速,按钮提交后禁用防止重复点击。倒计时结束前预加载接口,减少网络延迟影响。

php 抢购实现思路

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

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

相关文章

php实现打印功能

php实现打印功能

PHP 实现打印功能的方法 PHP 可以通过多种方式实现打印功能,具体取决于打印的目标(如打印机、PDF、网页等)和需求(如直接打印、生成打印预览等)。以下是几种常见的实现方式: 使用 JavaSc…

php实现验证码

php实现验证码

PHP实现验证码的方法 使用GD库生成验证码 GD库是PHP中处理图像的扩展,可用于生成验证码图片。 <?php session_start(); $width = 120; $height…

php 实现自动收货

php 实现自动收货

PHP 实现自动收货功能 自动收货功能通常用于电商系统,在订单超过一定时间未手动确认收货时自动完成订单。以下是实现方法: 数据库设计 需要订单表包含以下关键字段: CREATE TABLE ord…

php实现即时通讯

php实现即时通讯

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

php 实现下载

php 实现下载

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

php 队列的实现

php 队列的实现

PHP 队列的实现方法 使用数据库实现队列 创建一个数据表存储队列任务,包含任务ID、状态、创建时间等字段。通过SQL语句实现任务的入队和出队操作。 // 入队操作 INSERT INTO queu…