当前位置:首页 > PHP

php怎么实现抢购

2026-02-16 19:54:22PHP

PHP实现抢购功能

抢购功能需要解决高并发、库存准确性和防止超卖等问题。以下是实现抢购功能的关键步骤:

数据库设计

创建商品表和订单表,商品表需包含库存字段:

php怎么实现抢购

CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `stock` int(11) NOT NULL COMMENT '库存',
  `version` int(11) NOT NULL DEFAULT '0' COMMENT '乐观锁版本号',
  PRIMARY KEY (`id`)
);

CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `product_id` int(11) NOT NULL,
  `create_time` datetime NOT NULL,
  PRIMARY KEY (`id`)
);

悲观锁实现

使用数据库行锁确保同一时间只有一个请求能操作库存:

// 开启事务
$pdo->beginTransaction();
try {
    // 查询商品并加锁
    $stmt = $pdo->prepare("SELECT * FROM product WHERE id = ? FOR UPDATE");
    $stmt->execute([$productId]);
    $product = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($product['stock'] > 0) {
        // 减库存
        $pdo->prepare("UPDATE product SET stock = stock - 1 WHERE id = ?")->execute([$productId]);
        // 创建订单
        $pdo->prepare("INSERT INTO order (user_id, product_id, create_time) VALUES (?, ?, NOW())")->execute([$userId, $productId]);
        $pdo->commit();
        echo '抢购成功';
    } else {
        $pdo->rollBack();
        echo '库存不足';
    }
} catch (Exception $e) {
    $pdo->rollBack();
    echo '系统异常';
}

乐观锁实现

通过版本号控制并发:

php怎么实现抢购

$pdo->beginTransaction();
try {
    // 获取当前版本号
    $stmt = $pdo->prepare("SELECT stock, version FROM product WHERE id = ?");
    $stmt->execute([$productId]);
    $product = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($product['stock'] > 0) {
        // 带版本号更新
        $affected = $pdo->prepare("UPDATE product SET stock = stock - 1, version = version + 1 WHERE id = ? AND version = ?")
            ->execute([$productId, $product['version']]);

        if ($affected) {
            // 创建订单
            $pdo->prepare("INSERT INTO order (user_id, product_id, create_time) VALUES (?, ?, NOW())")->execute([$userId, $productId]);
            $pdo->commit();
            echo '抢购成功';
        } else {
            $pdo->rollBack();
            echo '抢购失败,请重试';
        }
    } else {
        $pdo->rollBack();
        echo '库存不足';
    }
} catch (Exception $e) {
    $pdo->rollBack();
    echo '系统异常';
}

Redis队列实现

使用Redis的原子操作处理高并发:

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

// 商品库存预先存入Redis
$redis->set("product_{$productId}_stock", 100);

// 扣减库存
$leftStock = $redis->decr("product_{$productId}_stock");
if ($leftStock >= 0) {
    // 库存足够,创建订单
    $orderId = createOrder($userId, $productId);
    if ($orderId) {
        echo '抢购成功';
    } else {
        // 回滚库存
        $redis->incr("product_{$productId}_stock");
        echo '创建订单失败';
    }
} else {
    // 库存不足回滚
    $redis->incr("product_{$productId}_stock");
    echo '库存不足';
}

限流措施

使用Redis实现简单限流:

$key = "user_{$userId}_limit";
$limit = 10; // 每秒限制10次请求

if ($redis->get($key) >= $limit) {
    die('请求过于频繁');
}
$redis->multi()
    ->incr($key)
    ->expire($key, 1)
    ->exec();

前端优化

  1. 倒计时结束后才显示购买按钮
  2. 按钮点击后立即禁用,防止重复提交
  3. 使用验证码或人机验证防止机器人

其他注意事项

  1. 库存预热:活动开始前将库存加载到Redis
  2. 异步处理:将订单创建放入消息队列异步处理
  3. 服务降级:核心功能优先保证,非核心功能可暂时关闭
  4. 数据一致性:最终通过定时任务核对Redis和数据库库存

以上方法可根据实际业务需求组合使用,悲观锁适合库存较少场景,乐观锁适合中等并发,Redis方案适合高并发场景。

标签: php
分享给朋友:

相关文章

php实现队列

php实现队列

PHP实现队列的方法 队列是一种先进先出(FIFO)的数据结构,PHP可以通过多种方式实现队列功能。 使用数组模拟队列 PHP数组可以模拟队列的基本操作,通过array_push和array_shi…

php实现

php实现

PHP 实现的基本方法 PHP 是一种服务器端脚本语言,广泛用于 Web 开发。以下是 PHP 实现的一些常见方法。 变量与数据类型 PHP 变量以 $ 开头,支持多种数据类型: $nam…

php长连接实现

php长连接实现

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

php实现推送

php实现推送

PHP 实现推送功能的方法 PHP 实现推送功能可以通过多种方式完成,包括 WebSocket、Server-Sent Events (SSE)、长轮询或第三方推送服务。以下是几种常见的方法: 使用…

php 实现秒杀

php 实现秒杀

PHP 实现秒杀的关键技术 秒杀系统需要解决高并发、超卖、性能瓶颈等问题。以下是实现秒杀的核心方案: 使用 Redis 预减库存 将商品库存提前加载到 Redis 中,通过原子操作保证库存准确性:…

php 实现单点登录

php 实现单点登录

PHP 实现单点登录的方法 单点登录(SSO)允许用户通过一次登录访问多个相互信任的系统。以下是基于 PHP 的实现方案: 基于共享 Session 的方案 在同一个主域名下的子域名间可以通过共享…