本文承接「環境與連接」篇,詳細講解 發出查詢 → 檢索結果集 → 處理行數據 → 釋放資源 的標準四步流程,重點對比 mysql_store_result(緩存全量)與 mysql_use_result(流式讀取)的適用場景、API 序列與完整示例代碼。
mysql_query(conn, sql) — 發送 SQL,0 成功。mysql_store_result(conn) 或 mysql_use_result(conn) — 獲取結果集句柄 MYSQL_RES*。mysql_fetch_row(res) — 逐行取得 MYSQL_ROW(char**),返回 NULL 結束。mysql_free_result(res) — 必須調用,釋放客戶端內存並通知 Server 清理臨時資源。mysql_store_result(緩存模式)MYSQL_RES *res = mysql_store_result(conn);
if (!res) { /* 錯誤處理 */ }
cout << "Total rows: " << mysql_num_rows(res) << '\n';
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
// 處理 row[0]...row[n-1]
}
mysql_free_result(res);
特點:一次性拉取所有行到客戶端內存,mysql_num_rows 立即可用,適合中小結果集;釋放快,不阻塞 Server。
mysql_use_result(流式模式)MYSQL_RES *res = mysql_use_result(conn);
if (!res) { /* 錯誤處理 */ }
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
// 處理行數據
}
mysql_free_result(res);
特點:按需從 Server 讀取,客戶端內存恆定;但 mysql_num_rows 需遍歷完才知總數;長時間持有會佔用 Server 線程、表鎖,嚴重影響併發,僅適合超大結果集且需流式處理的離線任務。
#include <iostream>
#include <mysql/mysql.h>
#include <string>
using namespace std;
void err(MYSQL *c) {
if (mysql_errno(c)) {
cerr << "Err " << mysql_errno(c) << ": " << mysql_error(c) << '\n';
exit(-1);
}
}
int main() {
MYSQL *conn = mysql_init(NULL);
if (!conn) err(conn);
if (!mysql_real_connect(conn, "localhost", "root", "123456", "test", 0, NULL, 0))
err(conn);
cout << "Connected.\n";
string sql;
getline(cin, sql);
if (mysql_query(conn, sql.c_str())) err(conn);
MYSQL_RES *res = mysql_store_result(conn);
if (!res) err(conn);
cout << "Retrieved " << mysql_num_rows(res) << " rows\n";
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
for (unsigned int i = 0; i < mysql_num_fields(res); ++i)
cout << (row[i] ? row[i] : "NULL") << '\t';
cout << '\n';
}
mysql_free_result(res);
mysql_close(conn);
return 0;
}
// ... 連接代碼同上 ...
MYSQL_RES *res = mysql_use_result(conn);
if (!res) err(conn);
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
// 直接寫入文件/網絡流,不留內存
fwrite(row[0], 1, strlen(row[0]), fp);
// ...
}
mysql_free_result(res);
| 錯誤現象 | 原因 | 修正 |
|---|---|---|
調用 mysql_num_rows 返回 0 但有數據 | 使用了 mysql_use_result 未遍歷完 | 改用 mysql_store_result 或先遍歷計數 |
| 程序卡住、CPU 100% | 流式模式下未及時 fetch_row,Server 端阻塞 | 加快消費速度或改用緩存模式 |
| 內存暴增 OOM | 緩存模式處理百萬行大結果集 | 分批查詢(LIMIT 分頁)或改用流式模式 |
| 二進制數據截斷/亂碼 | MYSQL_ROW 不含長度,遇 \0 截斷 | 配合 mysql_fetch_lengths(res) 獲取每列真實長度 |
下一篇預告:「結果集元數據獲取:列名、類型、長度、標誌、自增判斷」