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

使用循环将单个CSV导入MySQL多表时遇命令不同步错误求助

解决mysqli_multi_query导致的"Commands out of sync; you can't run this command now"错误

嘿,我之前也踩过这个坑,咱们来一步步搞定它。这个错误的核心原因是:当你用mysqli_multi_query执行多条语句后,没有处理完所有返回的结果集,MySQL连接会一直处于"等待处理结果"的状态,导致下一轮循环的查询无法执行。

先看你的代码问题

你在循环里每次都用mysqli_multi_query执行事务、插入、SELECT 433503这些语句,其中SELECT 433503会返回一个结果集。如果你不读取并释放这个结果集,MySQL就会认为上一次的查询还没完成,自然不让你执行下一次查询,就抛出了那个错误。

方案1:修复mysqli_multi_query的用法

如果你想继续用multi_query,那每次执行完后,必须把所有结果集都处理掉。在你的mysqli_multi_query后面加上这段代码:

mysqli_multi_query($db,$sql) or die("Error: ".mysqli_error($db));

// 关键:循环处理所有结果集,直到没有剩余
do {
    // 如果有结果集,就释放它
    if ($result = mysqli_store_result($db)) {
        mysqli_free_result($result);
    }
// 切换到下一个结果集,直到返回false
} while (mysqli_next_result($db));

这段代码会把multi_query执行后产生的所有结果(包括SELECT 433503的结果)都读取并释放,让连接回到可用状态,下一轮循环就能正常执行了。

方案2:更推荐的写法——拆分语句执行

其实mysqli_multi_query并不太适合这种场景,不仅容易出问题,代码也不好维护。更稳妥的方式是把每个语句分开执行,用mysqli_insert_id()来获取最后插入的ID,同时用事务API来管理提交和回滚:

$handle = fopen($file_tmp, 'r');
// 开启事务
mysqli_begin_transaction($db);

try {
    while (($myData = fgetcsv($handle,1000,';')) !== FALSE) {
        // 保留你原来的变量赋值
        $p1 = mysqli_real_escape_string($db,$myData[0]);
        $p2 = mysqli_real_escape_string($db,$myData[1]);
        // ... 省略其他p3到p22的赋值 ...
        $p22 = mysqli_real_escape_string($db,$myData[21]);

        // 1. 插入kualitas_produk
        $sql = "INSERT INTO `kualitas_produk`(`responden`,`p1`,`p2`,`p3`,`p4`,`p5`,`p6`,`p7`,`p8`,`p9`) VALUES ('','$p1','$p2','$p3','$p4','$p5','$p6','$p7','$p8','$p9');";
        mysqli_query($db, $sql) or throw new Exception(mysqli_error($db));
        
        // 获取最后插入的ID(替代SELECT 433503)
        $lastId = mysqli_insert_id($db);

        // 2. 插入harga_produk
        $sql = "INSERT INTO `harga_produk`(`responden`,`p10`,`p11`,`p12`) VALUES ('$lastId','$p10','$p11','$p12');";
        mysqli_query($db, $sql) or throw new Exception(mysqli_error($db));

        // 3. 插入keputusan_pembelian
        $sql = "INSERT INTO `keputusan_pembelian`(`responden`,`p13`,`p14`,`p15`,`p16`,`p17`,`p18`,`p19`,`p20`,`p21`,`p22`) VALUES ('$lastId', '$p13','$p14','$p15', '$p16','$p17','$p18', '$p19','$p20','$p21', '$p22');";
        mysqli_query($db, $sql) or throw new Exception(mysqli_error($db));

        // 4. 插入recap
        $sql = "INSERT INTO `recap`(`responden`,`kualitas`,`harga`,`keputusan`) VALUES ('$lastId','$lastId','$lastId','$lastId');";
        mysqli_query($db, $sql) or throw new Exception(mysqli_error($db));
    }

    // 所有数据插入成功,提交事务
    mysqli_commit($db);
    echo "Data Added";
} catch (Exception $e) {
    // 出错就回滚事务,避免部分数据插入
    mysqli_rollback($db);
    die("Error: " . $e->getMessage());
}

fclose($handle);
mysqli_close($db);

这个写法的好处:

  • 用mysqli_begin_transaction、mysqli_commit、mysqli_rollback来管理事务,比手动写START TRANSACTION和COMMIT更可靠;
  • 用mysqli_insert_id()直接获取最后插入的ID,不需要处理额外的结果集;
  • 出错时能及时回滚,保证数据的一致性;
  • 代码更清晰,调试起来也方便。

额外的优化建议

  1. 如果kualitas_produk表的responden是自增主键,那插入的时候可以省略这个字段,直接写:
INSERT INTO `kualitas_produk`(`p1`,`p2`,`p3`,`p4`,`p5`,`p6`,`p7`,`p8`,`p9`) VALUES ('$p1','$p2','$p3','$p4','$p5','$p6','$p7','$p8','$p9');

这样MySQL会自动生成自增ID,mysqli_insert_id()也能正确获取。

  1. 尽量使用预处理语句替代mysqli_real_escape_string,能更好地防止SQL注入,代码也更简洁。比如插入kualitas_produk可以改成:
$stmt = mysqli_prepare($db, "INSERT INTO `kualitas_produk`(`p1`,`p2`,`p3`,`p4`,`p5`,`p6`,`p7`,`p8`,`p9`) VALUES (?,?,?,?,?,?,?,?,?)");
// 绑定参数,'sssssssss'表示9个字符串类型的参数
mysqli_stmt_bind_param($stmt, 'sssssssss', $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9);
mysqli_stmt_execute($stmt);
$lastId = mysqli_stmt_insert_id($stmt);
mysqli_stmt_close($stmt);

这样就不用手动转义每个变量了,安全又高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:09:47