C 語言操作 MySQL 完整教程:API 詳解、連接池模式與 CRUD 實戰
C API (libmysqlclient) 是 MySQL 官方提供的最高性能、最底層的程式化介面。本文系統梳理核心數據結構、關鍵 API、標準交互流程,並給出連接、查詢、插入/刪除三大完整可編譯示例。
一、核心數據結構
| 結構體 | 用途 | 關鍵字段 |
MYSQL | 連接句柄 | host、user、socket、thread_id、server_status、options、methods |
MYSQL_RES | 結果集 | row_count、fields、data、data_cursor、lengths、handle |
MYSQL_ROW | 單行數據 | char ** 指針數組,row[i] 為第 i 列值(NULL 表示 SQL NULL) |
MYSQL_FIELD | 列元數據 | name、type、length、flags、decimals |
二、標準交互流程(五步法)
mysql_library_init():初始化客戶端庫(可選,mysql_init() 會自動調用)。
mysql_init(&mysql):分配/初始化 MYSQL 結構。
mysql_real_connect():建立 TCP/Unix Socket 連接,驗證身份,選擇默認庫。
- 業務循環:
mysql_real_query() / mysql_query() 發送 SQL。
mysql_store_result()(緩存全量)或 mysql_use_result()(流式)獲取結果集。
mysql_fetch_row() 逐行讀取,mysql_fetch_lengths() 獲取長度。
mysql_free_result() 釋放結果集內存。
mysql_close(&mysql) 斷開連接,mysql_library_end() 釋放庫資源。
三、關鍵 API 速查表
| 函數 | 用途 | 備註 |
mysql_real_connect() | 建立連接 | 支援 SSL、壓縮、多語句、自動重連等 flags |
mysql_real_query() | 執行 SQL(帶長度) | 二進制數據必須用此函數,避免 \\0 截斷 |
mysql_store_result() | 緩存完整結果集 | 支援隨機訪問、mysql_num_rows() 立即可用,大結果集慎用 |
mysql_use_result() | 流式讀取 | 內存佔用極低,但必須快速讀完,否則阻塞 Server |
mysql_fetch_row() | 取下一行 | 返回 MYSQL_ROW,末尾返回 NULL |
mysql_affected_rows() | 影響行數 | INSERT/UPDATE/DELETE 後調用 |
mysql_insert_id() | 自增 ID | 獲取上一條 INSERT 產生的 AUTO_INCREMENT 值 |
mysql_errno()/mysql_error() | 錯誤碼/信息 | 每次 API 調用後檢查,構建健壯錯誤處理 |
mysql_ping() | 心跳/重連 | 長連接場景定期調用,配合 MYSQL_OPT_RECONNECT |
四、完整示例代碼
1. 基礎連接測試(conn_test.c)
#include
#include
int main() {
MYSQL mysql;
if (!mysql_init(&mysql)) {
fprintf(stderr, "mysql_init() failed\n");
return -1;
}
if (!mysql_real_connect(&mysql, "localhost", "root", "shallnet", "db_users", 0, NULL, 0)) {
fprintf(stderr, "Connect failed: %s\n", mysql_error(&mysql));
return -1;
}
printf("✅ Connected to MySQL successfully!\n");
mysql_close(&mysql);
return 0;
}
2. 查詢數據(select_demo.c)
#include
#include
#include
int main() {
MYSQL mysql;
MYSQL_RES *res = NULL;
MYSQL_ROW row;
const char *query = "SELECT userid, username, birth, last_login FROM tb_users";
if (!mysql_init(&mysql) ||
!mysql_real_connect(&mysql, "localhost", "root", "shallnet", "db_users", 0, NULL, 0)) {
fprintf(stderr, "Init/Connect failed: %s\n", mysql_error(&mysql));
return -1;
}
if (mysql_real_query(&mysql, query, strlen(query))) {
fprintf(stderr, "Query failed: %s\n", mysql_error(&mysql));
return -1;
}
res = mysql_store_result(&mysql);
if (!res) {
fprintf(stderr, "Store result failed: %s\n", mysql_error(&mysql));
return -1;
}
int rows = mysql_num_rows(res);
int fields = mysql_num_fields(res);
printf("Total rows: %d, fields: %d\n", rows, fields);
while ((row = mysql_fetch_row(res))) {
for (int i = 0; i < fields; i++) {
printf("%s\t", row[i] ? row[i] : "NULL");
}
printf("\n");
}
mysql_free_result(res);
mysql_close(&mysql);
return 0;
}
3. 插入與刪除(crud_demo.c)
#include
#include
#include
int exec_sql(MYSQL *mysql, const char *sql) {
if (mysql_real_query(mysql, sql, strlen(sql))) {
fprintf(stderr, "SQL failed: %s\n%s\n", mysql_error(mysql), sql);
return -1;
}
printf("✅ Executed: %s (affected rows: %lu)\n", sql, (unsigned long)mysql_affected_rows(mysql));
return 0;
}
int main() {
MYSQL mysql;
if (!mysql_init(&mysql) ||
!mysql_real_connect(&mysql, "localhost", "root", "shallnet", "db_users", 0, NULL, 0)) {
fprintf(stderr, "Connect failed: %s\n", mysql_error(&mysql));
return -1;
}
// 插入測試數據
exec_sql(&mysql, "INSERT INTO tb_users (userid, username, birth) VALUES (12345, 'justtest', '2015-05-05')");
// 刪除舊數據
exec_sql(&mysql, "DELETE FROM tb_users WHERE userid = 10006");
// 驗證結果
const char *q = "SELECT userid, username, birth FROM tb_users ORDER BY userid";
if (!mysql_real_query(&mysql, q, strlen(q))) {
MYSQL_RES *res = mysql_store_result(&mysql);
if (res) {
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
printf("%s\t%s\t%s\n", row[0], row[1], row[2]);
}
mysql_free_result(res);
}
}
mysql_close(&mysql);
return 0;
}
五、編譯與鏈接