当前位置:首页 > PHP

php 实现秒杀功能

2026-02-15 08:33:18PHP

PHP实现秒杀功能的核心要点

秒杀场景的特点是高并发、低库存,需解决超卖、性能瓶颈、恶意请求等问题。以下是关键实现方案:

数据库设计优化

使用InnoDB引擎,利用事务和行锁保证数据一致性。商品表需包含stock字段(无符号整型)并设置乐观锁版本号:

php 实现秒杀功能

CREATE TABLE `seckill_goods` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `stock` int(11) unsigned NOT NULL COMMENT '剩余库存',
  `version` int(11) unsigned DEFAULT 0 COMMENT '乐观锁版本号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

悲观锁方案(MySQL行锁)

通过SELECT ... FOR UPDATE锁定记录,适合并发量中等场景:

php 实现秒杀功能

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

    if ($stock > 0) {
        $pdo->prepare("UPDATE seckill_goods SET stock = stock - 1 WHERE id = ?")->execute([$goods_id]);
        $pdo->commit();
        echo "秒杀成功";
    } else {
        $pdo->rollBack();
        echo "库存不足";
    }
} catch (Exception $e) {
    $pdo->rollBack();
    echo "系统异常";
}

乐观锁方案

通过版本号避免阻塞,适合高并发场景:

$pdo->beginTransaction();
try {
    // 先查询当前版本号
    $stmt = $pdo->prepare("SELECT stock, version FROM seckill_goods WHERE id = ?");
    $stmt->execute([$goods_id]);
    $data = $stmt->fetch(PDO::FETCH_ASSOC);

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

        if ($affected) {
            $pdo->commit();
            echo "秒杀成功";
        } else {
            $pdo->rollBack();
            echo "请重试";
        }
    } else {
        $pdo->rollBack();
        echo "库存不足";
    }
} catch (Exception $e) {
    $pdo->rollBack();
    echo "系统异常";
}

Redis原子操作

利用Redis的DECRWATCH实现原子减库存:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis_key = "seckill:goods:$goods_id";

// 监控库存键
$redis->watch($redis_key);
$stock = $redis->get($redis_key);

if ($stock > 0) {
    $redis->multi();
    $redis->decr($redis_key);
    $result = $redis->exec();

    if ($result) {
        echo "秒杀成功";
        // 异步更新数据库
    } else {
        echo "请重试";
    }
} else {
    $redis->unwatch();
    echo "库存不足";
}

流量削峰策略

  1. 前端限流:按钮倒计时+随机延迟提交
  2. 令牌桶算法:使用Redis实现请求速率限制
  3. 消息队列:将请求写入RabbitMQ/Kafka异步处理
// Redis令牌桶示例
$rate_limit_key = "user_limit:$user_id";
$limit = 10; // 每秒10次

if ($redis->lLen($rate_limit_key) < $limit) {
    $redis->lPush($rate_limit_key, time());
    $redis->expire($rate_limit_key, 1);
    // 处理请求
} else {
    echo "操作过于频繁";
}

防刷机制

  1. 隐藏秒杀接口:动态生成URL
  2. 验证码验证:复杂图形验证码
  3. 用户限购:Redis记录用户购买记录
  4. IP限制:Nginx层限制单IP访问频率

分层缓存架构

  1. Nginx缓存:静态页面缓存
  2. Redis集群:库存预热+热点数据缓存
  3. 数据库分库分表:降低单表压力

注意事项

  • 压测工具:使用JMeter模拟10万级并发测试
  • 库存预热:活动开始前将库存加载到Redis
  • 超时处理:设置合理的PHP脚本执行时间
  • 降级方案:库存售罄后直接返回静态页

实际部署时需根据业务规模选择组合方案,分布式环境需考虑Redis集群和分布式锁的实现。

标签: 功能秒杀
分享给朋友:

相关文章

vue实现拨号功能

vue实现拨号功能

Vue 实现拨号功能 使用 tel: 协议实现基础拨号 在 Vue 中可以通过 HTML 的 <a> 标签结合 tel: 协议实现拨号功能。这种方式适用于移动端浏览器,点击后会直接调用系统…

vue实现修改功能

vue实现修改功能

Vue 实现修改功能的方法 数据绑定与表单处理 使用v-model实现双向数据绑定,快速获取表单输入值。适用于表单类修改场景: <template> <input v-mode…

vue实现模板功能

vue实现模板功能

Vue 实现模板功能的方法 Vue.js 提供了多种方式来实现模板功能,包括使用插槽(Slots)、动态组件(Dynamic Components)以及渲染函数(Render Functions)。以…

vue 实现分页功能

vue 实现分页功能

实现分页功能的方法 在Vue中实现分页功能可以通过多种方式完成,以下是一种常见的实现方法: 使用计算属性处理分页数据 通过计算属性对数据进行分页处理,结合分页组件实现交互: <templat…

vue实现视频功能

vue实现视频功能

Vue 实现视频播放功能 使用 Vue 实现视频功能可以通过原生 HTML5 <video> 标签或第三方库(如 video.js)来实现。以下是两种常见方法: 使用原生 HTML5 &…

vue 实现登录功能

vue 实现登录功能

创建登录表单组件 在 Vue 项目中创建一个登录表单组件,通常命名为 Login.vue。该组件包含用户名和密码输入框,以及提交按钮。 <template> <form @su…