当前位置:首页 > PHP

php 抢购实现

2026-02-13 16:27:42PHP

抢购系统设计要点

高并发抢购系统的核心在于解决超卖、性能瓶颈和数据一致性问题。PHP实现需结合数据库、缓存和队列技术。

数据库层面优化

使用InnoDB引擎的事务和行级锁确保数据一致性。创建商品表时预留库存字段:

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

悲观锁实现方式:

$pdo->beginTransaction();
$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();
}

乐观锁实现

通过版本号控制并发:

$version = $pdo->query("SELECT version FROM seckill_goods WHERE id=$goods_id")->fetchColumn();
$affected = $pdo->exec("UPDATE seckill_goods SET stock=stock-1, version=version+1 
                       WHERE id=$goods_id AND version=$version");
if($affected > 0){
    // 抢购成功
}

Redis原子操作

使用Redis的DECR和Lua脚本保证原子性:

php 抢购实现

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$script = "
    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($script, ["goods_stock:$goods_id"], 1);

消息队列削峰

使用RabbitMQ或Redis List处理瞬时流量:

// 生产者
$redis->lPush('seckill_queue', json_encode(['user_id'=>$user_id, 'goods_id'=>$goods_id]));

// 消费者
while(true){
    $data = json_decode($redis->rPop('seckill_queue'), true);
    processOrder($data['user_id'], $data['goods_id']);
}

限流措施

使用Redis实现令牌桶限流:

function isAllowed($user_id){
    $key = "rate_limit:$user_id";
    $redis->multi()
          ->set($key, 10, ['NX', 'EX'=>60])
          ->decr($key)
          ->exec();
    return $redis->get($key) >= 0;
}

缓存预热

活动开始前将库存加载到Redis:

php 抢购实现

$stock = $pdo->query("SELECT stock FROM seckill_goods WHERE id=$goods_id")->fetchColumn();
$redis->set("goods_stock:$goods_id", $stock);

防脚本作弊

增加验证码机制:

// 生成验证码
$code = substr(md5(mt_rand()), 0, 4);
$_SESSION['seckill_code'] = $code;

// 校验验证码
if($_POST['code'] != $_SESSION['seckill_code']){
    die('验证码错误');
}

服务层优化

使用Swoole等常驻内存框架提升PHP性能:

$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->on('request', function ($request, $response) {
    $response->header("Content-Type", "text/plain");
    $response->end(handleSeckill());
});
$http->start();

数据一致性最终检查

通过定时任务核对Redis与数据库数据:

$redis_stock = $redis->get("goods_stock:$goods_id");
$db_stock = $pdo->query("SELECT stock FROM seckill_goods WHERE id=$goods_id")->fetchColumn();
if($redis_stock != $db_stock){
    // 触发报警并修复数据
}

标签: php
分享给朋友:

相关文章

php实现图片上传

php实现图片上传

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

php实现跳转

php实现跳转

PHP 实现页面跳转的方法 在 PHP 中实现页面跳转有多种方式,以下是常见的几种方法及其适用场景: 使用 header() 函数 通过 header() 函数发送 HTTP 头部信息实现跳转。注意…

php 实现下载

php 实现下载

PHP 实现文件下载的方法 使用 PHP 实现文件下载可以通过设置 HTTP 头信息,强制浏览器将文件作为附件下载而非直接打开。 基本下载实现 $file_path = 'path/to/your/…

php实现一个

php实现一个

PHP 实现一个简单的计算器 创建一个基本的计算器,支持加、减、乘、除运算。以下是一个完整的实现代码示例: <?php $result = ""; if ($_SERVER["REQUES…

php 实现链表

php 实现链表

PHP 实现链表的方法 链表是一种线性数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针。PHP 中可以通过类和对象来实现链表。 定义链表节点类 创建一个 ListNode 类,用于表示链…

php session 实现购物车

php session 实现购物车

PHP Session 实现购物车的方法 初始化 Session 在 PHP 脚本的最开始调用 session_start() 函数,确保会话已启用。这通常在页面的顶部完成。 session_sta…