MYSQL *mysql = mysql_init(NULL); // 1. 分配並初始化 MYSQL 結構體
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4"); // 可選:設定字元集
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); // 可選:連接超時
// 2. 建立真實連接 (推薦 mysql_real_connect,非 mysql_connect)
if (!mysql_real_connect(mysql,
"192.168.1.100", // host: 遠程服務器 IP
"app_user", // user
"StrongPass123!", // password
"business_db", // database
3306, // port
NULL, // unix_socket (TCP/IP 忽略)
0 // client_flag
)) {
fprintf(stderr, "Connection failed: %s\n", mysql_error(mysql));
mysql_close(mysql);
return -1;
}
// 3. 執行 SQL
if (mysql_query(mysql, "SELECT id, name FROM users WHERE status=1")) {
fprintf(stderr, "Query failed: %s\n", mysql_error(mysql));
} else {
MYSQL_RES *result = mysql_store_result(mysql); // 緩衝完整結果集
// 或 mysql_use_result(mysql) 逐行流式讀取 (大結果集)
while (MYSQL_ROW row = mysql_fetch_row(result)) {
printf("ID: %s, Name: %s\n", row[0], row[1] ? row[1] : "NULL");
}
mysql_free_result(result);
}
// 4. 關閉連接
mysql_close(mysql);
| API | 用途 | 推薦度 | 備註 |
|---|---|---|---|
| mysql_init() | 分配/初始化 MYSQL 結構體 | ✅ 必須 | 傳 NULL 自動分配 |
| mysql_real_connect() | 建立 TCP/IP 連接 (支援所有特性) | ✅ 必須 | 替代舊版 mysql_connect() |
| mysql_query() | 執行 SQL 陳述式 | ✅ 基礎 | 返回 0 成功 |
| mysql_store_result() | 將完整結果集讀入客戶端緩衝區 | ✅ 小/中結果集 | 隨機訪問、可獲取行數 |
| mysql_use_result() | 服務端逐行流式傳輸 | 大結果集/流式處理 | 佔用服務端資源、不可隨機訪問 |
| mysql_fetch_row() | 獲取下一行 (字串陣列) | ✅ 核心 | NULL 表示結束 |
| mysql_fetch_field() | 獲取欄位元數據 (名稱、型別、長度) | 動態構建對象 | 配合 mysql_num_fields() |
| mysql_affected_rows() | 獲取 INSERT/UPDATE/DELETE 影響行數 | ✅ 寫操作必查 | 返回 unsigned long long |
| mysql_insert_id() | 獲取最後 AUTO_INCREMENT 值 | ✅ 寫入後必查 | 需在同一連接內 |
| mysql_errno()/mysql_error() | 獲取最後錯誤碼/訊息 | ✅ 所有失敗分支 | 線程安全 |
| mysql_close() | 關閉連接、釋放資源 | ✅ 必須 | 即使連接失敗也要調用 |
C/C++ → General → Additional Include Directories:
$(MYSQL_INCLUDE_PATH) 或 C:\Program Files\MySQL\MySQL Server 8.0\include
Linker → General → Additional Library Directories:
$(MYSQL_LIB_PATH) 或 C:\Program Files\MySQL\MySQL Server 8.0\lib
Linker → Input → Additional Dependencies:
libmysql.lib
ws2_32.lib (Windows Socket 依賴)
原文提到「Linux 本身的密碼校驗」並嘗試「將數據庫用戶名密碼設置為和 Linux 一致」。這是**誤解**:
auth_socket 插件才會驗證 Linux 用戶名 (僅限本地 Unix Socket 連接),遠程 TCP/IP 連接**不適用**。-- 在 MySQL 服務器執行
CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'StrongPass123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON business_db.* TO 'app_user'@'192.168.1.%';
FLUSH PRIVILEGES;
-- 確保 bind_address = 0.0.0.0 (my.cnf) 並重啟
-- 防火牆放行 3306 埠
-- 客戶端使用上述 app_user / StrongPass123! 連接
MYSQL_STMT *stmt = mysql_stmt_init(mysql);
const char *query = "INSERT INTO logs (level, message) VALUES (?, ?)";
mysql_stmt_prepare(stmt, query, strlen(query));
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
// 綁定參數 1: level (tinyint)
unsigned char level = 3; // ERROR
bind[0].buffer_type = MYSQL_TYPE_TINY;
bind[0].buffer = &level;
bind[0].is_null = 0;
bind[0].length = 0;
// 綁定參數 2: message (varchar)
char msg[256] = "Disk full";
unsigned long msg_len = strlen(msg);
bind[1].buffer_type = MYSQL_TYPE_VAR_STRING;
bind[1].buffer = msg;
bind[1].buffer_length = sizeof(msg);
bind[1].length = &msg_len;
mysql_stmt_bind_param(stmt, bind);
mysql_stmt_execute(stmt);
printf("Inserted ID: %llu\n", mysql_stmt_insert_id(stmt));
mysql_stmt_close(stmt);
優勢:防 SQL 注入、重複執行只解析一次、二進位協議傳輸更高效。
// 自動重連 (MySQL 5.0.13+)
my_bool reconnect = 1;
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
// 手動重連邏輯 (更可控)
if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR ||
mysql_errno(mysql) == CR_SERVER_LOST) {
mysql_close(mysql);
mysql = mysql_init(NULL);
// 重新設置 options...
mysql_real_connect(...);
}
mysql_stmt_prepare + 批量綁定參數執行大量寫入。mysql_use_result + 逐行處理,避免客戶端 OOM。MySQL C API 雖然介面樸素,但作為所有高級語言連接器 (JDBC、ODBC、.NET、Python、Go) 的底層基石,掌握其核心流程、記憶體管理模型、錯誤碼語義,能幫助你在排查驅動層疑難雜症、編寫高效能原生客戶端、理解連接池實現原理時具備「透視眼」級洞察力。