在使用PHP 開發涉及MySQL 的應用時,有些開發者會通過mysql_info()或mysqli_info()來獲取執行某些SQL 操作後的補充信息,比如批量插入、更新或刪除語句影響的行數等。然而,有時你可能會發現返回的數據並不准確,甚至在某些操作之後直接返回false或空字符串。這種“不靠譜”的行為是怎麼回事?本文將從其工作原理出發,分析原因,並提供應對策略。
mysql_info()主要用於在執行某些非SELECT 語句後獲取執行狀態的簡要說明,比如:
$link = mysqli_connect("localhost", "user", "pass", "testdb");
mysqli_query($link, "UPDATE users SET status = 1 WHERE id < 100");
echo mysqli_info($link);
返回內容可能是:
Rows matched: 100 Changed: 100 Warnings: 0
這個輸出信息在調試批量操作時非常有用,比如判斷多少行被匹配,多少行被修改。但這依賴於底層MySQL 返回的狀態信息。
不是所有的非SELECT 操作都會生成info信息,MySQL 官方文檔也明確說明只有以下語句類型可能提供這些信息:
INSERT INTO ... SELECT ...
UPDATE
DELETE
LOAD DATA
像普通的INSERT 、 REPLACE等語句,尤其是沒有通過子查詢插入數據的場景,往往不會填充info 緩存。
PHP 使用的MySQL 客戶端庫(libmysql 或mysqlnd)也會影響info 的獲取。使用mysqlnd(MySQL native driver)時, mysqli_info()返回的內容更加可靠。而如果是libmysql,部分信息可能不會被記錄或延遲返回。
如果在一個連接中執行了多個SQL 語句(例如批處理), mysqli_info()只返回最後一條語句的info 信息。也就是說:
mysqli_query($link, "UPDATE table1 SET name = 'A'; UPDATE table2 SET name = 'B';");
echo mysqli_info($link); // 只會返回 table2 的執行信息
這讓很多開發者誤以為之前的操作沒有執行或沒有效果。
不同的MySQL 服務器版本在返回info 內容方面有差異。例如,舊版本可能不會統計Rows matched或Warnings ,或者存在bug 返回錯誤的行數信息。此外,如果啟用了某些性能優化選項,可能跳過了一些統計邏輯。
確保PHP 環境中啟用了mysqlnd 驅動,可以通過如下方式檢查:
if (function_exists('mysqli_get_client_stats')) {
echo "mysqlnd 已啟用";
}
mysqlnd 提供了更全面和標準化的info 支持,比libmysql 更推薦用於生產環境。
不要在多語句(multi_query)中依賴info 的返回,應該將每個語句單獨執行,並立即讀取對應的info 信息,以防止被後續語句覆蓋。
mysqli_query($link, "DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY");
$logInfo = mysqli_info($link);
echo "日誌清理結果:" . $logInfo;
對於一些重要的SQL 操作,建議不要完全依賴mysql_info()返回的文本描述,而是根據業務邏輯做一次額外的查詢或日誌記錄來驗證。例如清理前後行數差值,或通過事務控制確保精確執行。
注意Changed: 0並不意味著SQL 沒有成功執行,可能只是數據本身未發生變化(例如更新成了相同的值)。這種場景在UPDATE中很常見,也解釋了為什麼你看到有Rows matched卻Changed: 0的情況。
為了更有效地調試和記錄,可以使用如下方式將info 信息寫入日誌或展示到後台界面:
$sql = "UPDATE users SET status = 0 WHERE active = 0";
mysqli_query($link, $sql);
file_put_contents("/var/log/mysql_ops.log", date('Y-m-d H:i:s') . " " . $sql . " => " . mysqli_info($link) . "\n", FILE_APPEND);
也可以將這些操作記錄通過接口發送到遠程監控系統:
$url = "https://m66.net/log_sql_info";
$data = ['sql' => $sql, 'info' => mysqli_info($link)];
// 使用 curl 或 Guzzle 發送 POST 請求
mysql_info()或mysqli_info()是一個有用但有限的工具,它提供的是對SQL 操作的補充性信息,不應成為判斷邏輯成功與否的唯一依據。在不同驅動、MySQL 版本和語句類型的條件下,它可能表現不一。開發者應深入理解其局限,結合日誌、事務、返回碼等方式進行全面監控和容錯設計,才能構建健壯的數據庫操作流程。