当前位置: 首页> 最新文章列表> 使用 mysqli::get_warnings 检测批量 INSERT 时的重复键问题

使用 mysqli::get_warnings 检测批量 INSERT 时的重复键问题

gitbox 2025-05-29

为什么需要用 mysqli::get_warnings()

在执行批量 INSERT 操作时,如果使用了 INSERT IGNOREON DUPLICATE KEY UPDATE,MySQL 并不会直接报错,而是生成警告(warnings)。这时候,我们很难通过错误捕捉机制得知具体的冲突信息。mysqli::get_warnings() 可以拿到这些警告,帮助我们理解哪些记录发生了冲突。

示例代码

假设有如下数据表 users,定义了一个唯一键 email

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50),
  email VARCHAR(100) UNIQUE
);

我们尝试批量插入多条数据,其中包含重复的 email

<?php
$mysqli = new mysqli("localhost", "root", "password", "testdb");

if ($mysqli->connect_errno) {
    die("连接数据库失败: " . $mysqli->connect_error);
}

// 预备批量插入的SQL语句
$sql = "INSERT IGNORE INTO users (name, email) VALUES 
        ('Alice', '[email protected]'), 
        ('Bob', '[email protected]'),
        ('Charlie', '[email protected]')";  // 注意这里的email重复

if ($mysqli->query($sql)) {
    echo "插入完成。<br>";

    // 通过 get_warnings() 检测是否有重复键冲突警告
    if ($warning = $mysqli->get_warnings()) {
        do {
            echo "警告级别: " . $warning->get_errno() . "<br>";
            echo "警告消息: " . $warning->get_message() . "<br>";
        } while ($warning->next());
    } else {
        echo "无警告信息。";
    }
} else {
    echo "插入失败: " . $mysqli->error;
}

$mysqli->close();

在上面代码中,我们用 INSERT IGNORE 来尝试插入数据。当遇到重复的 email 时,MySQL 会忽略该条记录的插入,但会生成警告。通过 $mysqli->get_warnings() 可以获取这些警告信息,从而知道存在重复键冲突。

mysqli_warning 对象详解

mysqli::get_warnings() 返回的是一个 mysqli_warning 对象,可以调用以下方法获取详细信息:

  • get_errno():获取警告的错误码

  • get_message():获取警告消息文本

  • next():移动到下一个警告(如果有)

通常,重复键冲突的警告码是 1062,对应消息中会包含“Duplicate entry”。

注意事项

  1. 如果不使用 INSERT IGNORE 或类似的策略,重复键冲突会直接导致查询失败,返回错误而非警告。

  2. get_warnings() 返回的是警告链,需要循环遍历获取所有警告。

  3. 警告信息内容较为详细,可以用来精确定位冲突的记录。


通过 mysqli::get_warnings(),我们可以在批量插入时更加优雅地处理重复键冲突,不仅保证数据插入的连续性,还能及时获知数据质量问题,提高程序的健壮性。


<?php
$mysqli = new mysqli("localhost", "root", "password", "testdb");

if ($mysqli->connect_errno) {
    die("连接数据库失败: " . $mysqli->connect_error);
}

$sql = "INSERT IGNORE INTO users (name, email) VALUES 
        ('Alice', '[email protected]'), 
        ('Bob', '[email protected]'),
        ('Charlie', '[email protected]')";

if ($mysqli->query($sql)) {
    echo "插入完成。<br>";

    if ($warning = $mysqli->get_warnings()) {
        do {
            echo "警告级别: " . $warning->get_errno() . "<br>";
            echo "警告消息: " . $warning->get_message() . "<br>";
        } while ($warning->next());
    } else {
        echo "无警告信息。";
    }
} else {
    echo "插入失败: " . $mysqli->error;
}

$mysqli->close();