支持一次調用執行多條 SQL(以分號分隔),適用於批量 DML、DDL、混合語句。注意:返回結果集時需循環處理所有結果集,否則會導致「Commands out of sync」錯誤。
<?php
$mysqli = new mysqli("localhost", "root", "root", "test");
if ($mysqli->connect_errno) die("連接失敗: " . $mysqli->connect_error);
$sql = "INSERT INTO user1 (name, password, email, age) VALUES ('AAA', MD5('AAA'), 'AAA@hu.com', 25);";
$sql .= "INSERT INTO user1 (name, password, email, age) VALUES ('BBB', MD5('BBB'), 'BBB@hu.com', 25);";
$sql .= "INSERT INTO user1 (name, password, email, age) VALUES ('CCC', MD5('CCC'), 'CCC@hu.com', 25);";
// 可混合:$sql .= "UPDATE user1 SET age=15 WHERE id=1; DELETE FROM user1 WHERE id=10;";
if ($mysqli->multi_query($sql)) {
echo "批量執行成功,影響行數: " . $mysqli->affected_rows;
} else {
echo "執行失敗: " . $mysqli->error;
}
$mysqli->close();
<?php
$mysqli = new mysqli("localhost", "root", "root", "test");
if ($mysqli->connect_errno) die("連接失敗: " . $mysqli->connect_error);
$sql = "SELECT * FROM user1;";
$sql .= "DESC user1;"; // 第二條查詢
if ($mysqli->multi_query($sql)) {
do {
// 獲取當前結果集
if ($result = $mysqli->store_result()) {
echo "=== 結果集 ===" . "<br>";
while ($row = $result->fetch_row()) {
foreach ($row as $val) echo "--$val";
echo "<br>";
}
$result->free(); // 必須釋放,否則內存洩漏
} else {
// 無結果集的語句(INSERT/UPDATE),affected_rows 可用
echo "無結果集語句,影響行數: " . $mysqli->affected_rows . "<br>";
}
// 檢查是否還有下一個結果集
if ($mysqli->more_results()) {
echo "******** 新結果集 ********<br>";
} else {
break;
}
} while ($mysqli->next_result()); // 移動到下一個結果集
} else {
echo "執行失敗: " . $mysqli->error;
}
$mysqli->close();
multi_query(sql)
│
├─► store_result() ──► fetch_row() 循環 ──► free()
│
├─► more_results() ? ── 是 ──► next_result() ──► 循環
│
└─► 否 ──► 結束
| 錯誤 | 原因 | 解決 |
|---|---|---|
| Commands out of sync | 未處理完所有結果集就執行下一條查詢 | 務必循環 next_result() 直到 more_results() 為 false |
| 內存耗盡 | 大結果集未及時 free() | 每個結果集用完立即 $result->free() |
| SQL 語法錯誤導致後續不執行 | multi_query 遇錯誤停止 | 單獨測試每條 SQL;或拆分為多次 multi_query |
| 預處理語句不能用 multi_query | prepare() 單條執行 | 批量寫入用事務 + prepare 循環 execute |
// 方案 A:multi_query(網絡往返 1 次,但無法參數化,防注入弱)
$mysqli->multi_query($hugeSql);
// 方案 B:事務 + prepare(推薦,安全、可複用執行計劃)
$mysqli->begin_transaction();
$stmt = $mysqli->prepare("INSERT INTO t (a,b) VALUES (?,?)");
foreach ($data as $row) {
$stmt->bind_param('ss', $row['a'], $row['b']);
$stmt->execute();
}
$mysqli->commit();
結論:批量寫入優先用 事務 + 預處理;multi_query 適合導入 SQL 文件、執行 DDL 腳本、混合無參數語句。
PDO 無對應方法,需自行分割 SQL 字符串循環 exec(),或使用事務 + 預處理。
multi_query,極高風險 SQL 注入。