当前位置:首页 > PHP

php秒杀 实现过程

2026-02-27 10:48:58PHP

数据库设计

创建商品表和订单表,商品表需包含库存字段(stock),订单表记录秒杀成功的用户信息。使用事务和锁机制确保数据一致性。

CREATE TABLE `seckill_goods` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `stock` int(11) NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `seckill_orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `goods_id` int(11) NOT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
);

悲观锁实现

在事务中使用SELECT...FOR UPDATE锁定商品记录,防止其他请求同时修改库存。检查库存充足后执行减库存和创建订单操作。

$pdo->beginTransaction();
try {
    $stmt = $pdo->prepare("SELECT stock FROM seckill_goods WHERE id = ? FOR UPDATE");
    $stmt->execute([$goodsId]);
    $stock = $stmt->fetchColumn();

    if ($stock > 0) {
        $pdo->prepare("UPDATE seckill_goods SET stock = stock - 1 WHERE id = ?")->execute([$goodsId]);
        $pdo->prepare("INSERT INTO seckill_orders (user_id, goods_id) VALUES (?, ?)")->execute([$userId, $goodsId]);
    }
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}

乐观锁实现

通过版本号或条件更新实现,在UPDATE语句中增加库存判断条件,利用affectedRows判断是否秒杀成功。

$pdo->beginTransaction();
try {
    $affected = $pdo->prepare("UPDATE seckill_goods SET stock = stock - 1 WHERE id = ? AND stock > 0")
              ->execute([$goodsId]);

    if ($affected > 0) {
        $pdo->prepare("INSERT INTO seckill_orders (user_id, goods_id) VALUES (?, ?)")
            ->execute([$userId, $goodsId]);
    }
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}

缓存预热

将商品信息加载到Redis,使用原子操作DECR处理库存。避免频繁访问数据库,Lua脚本保证操作原子性。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->set("goods_stock_{$goodsId}", 100); // 初始化库存

$lua = "
local stock = tonumber(redis.call('get', KEYS[1]))
if stock > 0 then
    redis.call('decr', KEYS[1])
    return 1
end
return 0
";

$result = $redis->eval($lua, ["goods_stock_{$goodsId}"], 1);
if ($result) {
    // 秒杀成功,异步处理数据库
}

请求限流

使用Redis计数器限制单位时间内的请求量,防止系统过载。结合IP和用户ID进行更细粒度的控制。

$key = 'seckill_rate_limit_' . date('YmdHi');
$redis->multi();
$redis->incr($key);
$redis->expire($key, 60);
$redis->exec();

if ($redis->get($key) > 1000) {
    header('HTTP/1.1 429 Too Many Requests');
    exit;
}

异步处理

将秒杀请求放入消息队列(如RabbitMQ),后台消费者顺序处理。实现流量削峰,提高系统吞吐量。

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('seckill_queue', false, true, false, false);

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

$channel->basic_publish($msg, '', 'seckill_queue');
$channel->close();
$connection->close();

防作弊措施

验证用户身份和请求合法性,限制单个用户购买数量。使用隐藏表单令牌防止CSRF攻击。

session_start();
$token = md5(uniqid());
$_SESSION['seckill_token'] = $token;

// 在表单中输出
<input type="hidden" name="token" value="<?php echo $token; ?>">

// 提交时验证
if (empty($_POST['token']) || $_POST['token'] !== $_SESSION['seckill_token']) {
    die('非法请求');
}

php秒杀 实现过程

标签: 过程秒杀
分享给朋友:

相关文章

php实现秒杀

php实现秒杀

PHP实现秒杀功能的关键技术 秒杀系统需要解决高并发、数据一致性、系统稳定性等问题。以下是PHP实现秒杀功能的核心技术方案: 数据库优化 使用InnoDB引擎的行级锁和事务特性,确保数据一致性。商品…

vue watch实现过程

vue watch实现过程

Vue Watch 的实现过程 Vue 的 watch 用于监听响应式数据的变化,并在数据变化时执行回调函数。以下是其核心实现过程: 初始化 Watcher 在 Vue 实例初始化阶段,如果组件选项…

vue实现spa的过程

vue实现spa的过程

Vue 实现 SPA 的基本流程 安装 Vue 及相关依赖 通过 npm 或 yarn 安装 Vue 核心库和 Vue Router(用于路由管理): npm install vue vue-ro…

php评论实现过程

php评论实现过程

实现PHP评论功能的基本过程 数据库设计 创建数据库表存储评论信息,通常包含字段:评论ID、用户ID、内容、发布时间、关联文章ID等。示例SQL: CREATE TABLE comments (…

js实现汉诺塔移动过程

js实现汉诺塔移动过程

汉诺塔问题概述 汉诺塔(Tower of Hanoi)是一个经典的递归问题,目标是将一组盘子从起始柱移动到目标柱,遵循以下规则: 每次只能移动一个盘子。 每次移动时,将最上面的盘子移动到某一柱上。…

秒杀 js 实现

秒杀 js 实现

秒杀功能的实现要点 前端实现秒杀功能需要处理高并发、时间同步、防刷等问题。以下是基于JavaScript的核心实现逻辑: 倒计时功能 使用定时器实现秒杀倒计时,需确保与服务器时间同步: f…