承接前兩篇,本文聚焦 結果集檢索的兩種模式(mysql_store_result vs mysql_use_result)、逐行處理、列元數據獲取(列名、類型、長度、標誌),並提供兩個可直接編譯運行的完整示例。
| 特性 | mysql_store_result | mysql_use_result |
|---|---|---|
| 數據傳輸 | 一次性將全結果集從 Server 拉取到 Client 內存 | 按需流式讀取,Server 端保持結果集 |
| Client 內存佔用 | 大(與結果集大小成正比) | 小(僅當前行) |
mysql_num_rows 可用性 | 立即可用,準確 | 需遍歷完才知總行數,調用前返回 0 |
| 適用場景 | 中小結果集、需隨機訪問、需預知行數 | 大結果集、流式處理、內存受限環境 |
| 併發影響 | 釋放 Server 資源快 | 長時間佔用 Server 線程與表鎖,慎用 |
MYSQL_RES *mysql_store_result(MYSQL *conn);
MYSQL_RES *mysql_use_result(MYSQL *conn);
MYSQL_ROW mysql_fetch_row(MYSQL_RES *res); // 返回 NULL 表示結束或出錯
unsigned int mysql_num_rows(MYSQL_RES *res); // 僅 store_result 可靠
unsigned int mysql_num_fields(MYSQL_RES *res); // 列數
void mysql_free_result(MYSQL_RES *res); // 必須調用,釋放客戶端/服務端資源
mysql_store_result)#include <iostream>
#include <mysql/mysql.h>
using namespace std;
void err(MYSQL *c) {
if (mysql_errno(c)) {
cerr << "Err " << mysql_errno(c) << ": " << mysql_error(c) << '\n';
exit(-1);
}
}
void print_row(MYSQL *conn, MYSQL_ROW row) {
for (unsigned int i = 0; i < mysql_field_count(conn); ++i)
cout << (row[i] ? row[i] : "NULL") << ' ';
cout << '\n';
}
int main() {
MYSQL *conn = mysql_init(NULL);
if (!mysql_real_connect(conn, "localhost", "root", "123456", "test", 0, NULL, 0))
err(conn);
if (mysql_query(conn, "SELECT * FROM tmp15")) err(conn);
MYSQL_RES *res = mysql_store_result(conn);
if (!res) err(conn);
MYSQL_ROW row;
while ((row = mysql_fetch_row(res)))
print_row(conn, row);
mysql_free_result(res);
mysql_close(conn);
return 0;
}
MYSQL_FIELDtypedef struct st_mysql_field {
char *name; // 列名
char *table; // 所屬表名
char *org_table; // 原始表名(別名時)
char *db; // 數據库名
char *def; // 默認值
unsigned long length; // 列定義寬度
unsigned long max_length; // 結果集中最大顯示寬度
unsigned int flags; // 標誌位(NOT_NULL, PRI_KEY, AUTO_INCREMENT...)
unsigned int decimals;// 小數位數
enum enum_field_types type; // 類型代碼
} MYSQL_FIELD;
IS_NUM(field->type) // 數值類型
field->type == FIELD_TYPE_VAR_STRING // VARCHAR
field->type == FIELD_TYPE_LONG // INT
field->flags & AUTO_INCREMENT_FLAG // 自增列
void print_metadata(MYSQL_RES *res) {
MYSQL_FIELD *field;
cout << "Column Describe:\n";
while ((field = mysql_fetch_field(res))) {
cout << "\tName: " << field->name << '\n';
cout << "\tType: ";
if (IS_NUM(field->type)) cout << "Numeric";
else {
switch(field->type) {
case FIELD_TYPE_VAR_STRING: cout << "Varchar"; break;
case FIELD_TYPE_LONG: cout << "Long"; break;
default: cout << "Type code " << field->type;
}
}
cout << "\n\tMax width: " << field->length << '\n';
if (field->flags & AUTO_INCREMENT_FLAG)
cout << "\tAUTO_INCREMENT\n";
cout << '\n';
}
mysql_field_seek(res, 0); // 重置游標,以便後續 fetch_row
}
g++ -lmysqlclient demo3.cc -o demo3
./demo3
關鍵提醒:
MYSQL_ROW 只是 char**,不含長度信息;含 NULL 或二進制數據時必須配合 mysql_fetch_lengths(res) 使用。mysql_free_result,否則會洩漏內存並導致 Server 端臨時表殘留。mysql_use_result 會阻塞其他寫入,生產環境優先 mysql_store_result 或限制查詢規模。