You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP MySQL实现ID重复时累加更新quantity列的方法

PHP操作MySQL实现ID重复时累加quantity字段方案

核心实现原理

直接使用MySQL原生提供的INSERT ... ON DUPLICATE KEY UPDATE原子语法实现,不需要提前查询记录是否存在,天然避免高并发下的竞态问题,执行逻辑为:

  1. 尝试执行插入操作
  2. 如果插入时碰到主键/唯一索引冲突(即待插入ID已存在的情况),则执行后续定义的更新操作
  3. 不存在冲突则正常插入新记录

前置要求

必须给id字段设置主键约束或者唯一索引,否则MySQL无法识别ID重复的冲突,会直接插入重复ID的脏数据。

代码示例(PDO写法,PHP官方推荐的数据库操作方式)

<?php
// 数据库连接配置
$host = '127.0.0.1';
$dbname = '你的业务库名';
$dbUser = '你的数据库账号';
$dbPwd = '你的数据库密码';

try {
    // 初始化连接,强制utf8mb4字符集
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $dbUser, $dbPwd);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // 业务侧待写入数据,实际场景替换成你的业务取值逻辑即可
    $rowData = [
        'id' => 1024, // 待写入的记录ID
        'quantity' => 5, // 本次需要新增/累加的数量值
        'goods_name' => '机械键盘' // 其他业务字段示例
    ];

    // 核心SQL:冲突时仅累加quantity字段,不修改其他字段
    $sql = "INSERT INTO goods_stock (id, quantity, goods_name)
            VALUES (:id, :quantity, :goods_name)
            ON DUPLICATE KEY UPDATE
            quantity = quantity + :incr_quantity";
    
    $stmt = $pdo->prepare($sql);
    // 绑定参数,防SQL注入
    $stmt->bindValue(':id', $rowData['id'], PDO::PARAM_INT);
    $stmt->bindValue(':quantity', $rowData['quantity'], PDO::PARAM_INT);
    $stmt->bindValue(':goods_name', $rowData['goods_name'], PDO::PARAM_STR);
    // 累加值单独绑定,兼容不同PDO驱动不支持同参数多次复用的问题
    $stmt->bindValue(':incr_quantity', $rowData['quantity'], PDO::PARAM_INT);

    $stmt->execute();

    // 可选:根据影响行数判断操作类型
    $affectRows = $stmt->rowCount();
    if ($affectRows === 1) {
        // 无冲突,新记录插入完成
        echo "新记录插入成功";
    } elseif ($affectRows === 2) {
        // 触发冲突,执行了更新累加
        echo "ID已存在,库存数量累加完成";
    }

} catch (PDOException $e) {
    die("数据库操作出错:" . $e->getMessage());
}

关键注意事项

  • 禁止用「先SELECT查询ID是否存在,再走插入/更新分支」的写法,高并发场景下两个请求同时查到ID不存在,都会走插入逻辑,会导致数量计算错误、主键冲突报错等问题,INSERT ... ON DUPLICATE KEY UPDATE是数据库层面原子操作,不存在这个问题。
  • 禁止用REPLACE INTO实现需求,该语法的逻辑是检测到冲突后先删除旧记录、再插入新记录,会清空其他字段的原有值,还会导致自增ID异常跳涨,完全不适合累加场景。
  • 如果需要在ID冲突时同步更新其他字段,直接在ON DUPLICATE KEY UPDATE子句后追加即可,比如要更新最后修改时间可以加update_time = NOW(),不需要更新的字段不要写到该子句中,会保留原有值。
  • 如果项目用的是MySQLi扩展,核心SQL语句完全不需要修改,只需要把PDO的绑定、执行逻辑换成MySQLi对应预处理写法即可。

内容的提问来源于stack exchange,提问作者Jones Moura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 06:39:28