当前位置:首页 > PHP

php 实现抢购

2026-01-29 18:00:12PHP

抢购系统设计要点

抢购系统需要解决高并发、库存超卖、系统稳定性等问题。以下是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,
  `product_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
);

乐观锁实现

通过版本号控制并发更新:

$pdo->beginTransaction();
try {
    // 查询商品信息并锁定行
    $stmt = $pdo->prepare("SELECT stock, version FROM product WHERE id = ? FOR UPDATE");
    $stmt->execute([$productId]);
    $product = $stmt->fetch(PDO::FETCH_ASSOC);

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

        if ($update->rowCount() > 0) {
            // 创建订单
            $pdo->prepare("INSERT INTO `order` (product_id, user_id) VALUES (?, ?)")
                ->execute([$productId, $userId]);
            $pdo->commit();
            return true;
        }
    }
    $pdo->rollBack();
    return false;
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}

缓存预热

使用Redis预存商品库存,避免直接穿透到数据库:

php 实现抢购

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 活动开始前初始化库存
$redis->set("product_stock_{$productId}", 100);

原子计数器

通过Redis的原子操作保证库存扣减:

$remaining = $redis->decr("product_stock_{$productId}");
if ($remaining >= 0) {
    // 进入订单创建流程
} else {
    // 库存不足
    $redis->incr("product_stock_{$productId}"); // 回滚
}

限流措施

使用Redis实现令牌桶限流:

php 实现抢购

$rateLimitKey = "rate_limit_{$productId}";
$limit = 100; // 每秒100个请求

if ($redis->exists($rateLimitKey)) {
    $current = $redis->incr($rateLimitKey);
    if ($current > $limit) {
        http_response_code(429);
        exit('Too many requests');
    }
} else {
    $redis->setex($rateLimitKey, 1, 1);
}

异步处理

将订单创建放入消息队列缓解压力:

// 使用RabbitMQ
$connection = new AMQPConnection(['host' => '127.0.0.1']);
$channel = $connection->channel();
$channel->queue_declare('order_queue', false, true, false, false);

$msg = new AMQPMessage(json_encode([
    'product_id' => $productId,
    'user_id' => $userId
]));

$channel->basic_publish($msg, '', 'order_queue');

防机器人脚本

添加验证码机制:

session_start();
if ($_POST['captcha'] !== $_SESSION['captcha']) {
    die('验证码错误');
}

系统监控

实现实时监控关键指标:

// 使用Prometheus客户端
$gauge = new Gauge('seckill_requests_total', 'Total requests');
$gauge->inc(); // 请求计数

以上方案需根据实际业务场景调整,测试阶段应进行压力测试验证系统承载能力。分布式环境需考虑使用分布式锁替代单机锁方案。

标签: php
分享给朋友:

相关文章

php实现文件下载

php实现文件下载

PHP 实现文件下载的方法 使用 header() 函数强制下载 设置正确的 HTTP 头信息,强制浏览器下载文件而不是直接打开。 $file = 'path/to/file.pdf'; if (…

php实现分页

php实现分页

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

php实现图片上传

php实现图片上传

实现图片上传的基本步骤 创建HTML表单用于文件上传,表单需设置enctype="multipart/form-data"属性,确保文件数据正确传输。 <form action="uploa…

php实现定时任务

php实现定时任务

PHP 实现定时任务的几种方法 在 PHP 中实现定时任务可以通过多种方式完成,具体选择取决于项目需求和服务器环境。以下是常见的实现方法: 使用 Cron 任务 Cron 是 Linux 系统中常用…

php购物车实现

php购物车实现

PHP购物车实现方法 使用PHP实现购物车功能可以通过多种方式完成,以下是几种常见的实现方法: Session存储购物车数据 利用PHP的$_SESSION超全局变量存储购物车数据是最简单的方法。用…

php 实现接口

php 实现接口

PHP 实现接口的方法 在 PHP 中,接口(Interface)用于定义一组方法的规范,而不包含具体的实现。类可以实现(implement)接口,并必须实现接口中定义的所有方法。 定义接口 接口通…