当前位置:首页 > PHP

php怎么实现抢购

2026-02-16 19:54:22PHP

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 '系统异常';
}

乐观锁实现

通过版本号控制并发:

$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实现简单限流:

php怎么实现抢购

$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实现分页的基本方法 使用LIMIT和OFFSET进行数据库查询分页。通过计算当前页码和每页显示数量,动态生成SQL语句。 $page = isset($_GET['page']) ? (int…

php实现socket

php实现socket

PHP 实现 Socket 通信 PHP 可以通过 socket 扩展实现网络通信,支持 TCP/UDP 协议。以下是实现 Socket 通信的核心步骤和代码示例。 创建 TCP 服务器 // 创建…

php 实现登录

php 实现登录

PHP 登录功能实现 使用 PHP 实现登录功能通常需要结合数据库验证和会话管理。以下是一个基本的登录实现流程: 数据库准备 创建用户表存储用户名和密码(建议使用哈希加密): CREATE TAB…

php 登录实现

php 登录实现

PHP 登录实现 PHP 登录功能通常包括用户认证、会话管理和安全性措施。以下是实现 PHP 登录功能的关键步骤。 数据库准备 创建一个用户表存储用户信息,通常包括用户名、密码(加密存储)和其他必要…

php 实现购物车

php 实现购物车

PHP 实现购物车功能 购物车功能是电子商务网站的核心部分,可以通过 PHP 和 Session 或数据库来实现。以下是两种常见的实现方式: 使用 Session 存储购物车数据 Session 是…

php实现的分页

php实现的分页

PHP 实现分页的方法 基本分页逻辑 分页的核心在于计算总页数、当前页码以及数据偏移量。假设每页显示 10 条数据: $current_page = isset($_GET['page']) ? (…