MySQL C API (libmysqlclient) 是所有高級語言驅動的基石,掌握它能深入理解驅動原理、編寫高效能嵌入式應用。本文涵蓋環境構建、連接管理、非查詢/查詢執行、結果集遍歷、預處理語句、事務控制、錯誤處理、資源釋放完整流程。
# Ubuntu/Debian
sudo apt-get install libmysqlclient-dev
# CentOS/RHEL
sudo yum install mysql-devel
# 編譯鏈接
gcc -o myapp myapp.c $(mysql_config --cflags --libs)
# 或手動
gcc -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient -o myapp myapp.c
#include
#include
#include
#include
MYSQL *conn = mysql_init(NULL); // 分配並初始化 MYSQL 結構
if (!conn) {
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
// 可選:設置連接選項 (連接前調用)
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");
mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &(int){5});
mysql_options(conn, MYSQL_OPT_RECONNECT, &(my_bool){1});
if (!mysql_real_connect(conn,
"localhost", // host
"app_user", // user
"secure_pass", // password
"test_db", // database
3306, // port
NULL, // unix_socket
0)) { // client_flag
fprintf(stderr, "Connect failed: %s\n", mysql_error(conn));
mysql_close(conn);
exit(1);
}
printf("Connected to MySQL %s\n", mysql_get_server_info(conn));
const char *sql = "INSERT INTO users (name, email) VALUES ('Zhang San', 'zhang@example.com')";
if (mysql_query(conn, sql)) {
fprintf(stderr, "Insert failed: %s\n", mysql_error(conn));
} else {
printf("Inserted %llu rows, Last Insert ID: %llu\n",
(unsigned long long)mysql_affected_rows(conn),
(unsigned long long)mysql_insert_id(conn));
}
關鍵函數:
mysql_affected_rows():返回影響行數 (類型 my_ulonglong,打印用 %llu 轉 unsigned long long)。mysql_insert_id():返回自增主鍵值。mysql_errno() / mysql_error():錯誤代碼與信息。if (mysql_query(conn, "SELECT id, name, email FROM users WHERE id > 0")) {
fprintf(stderr, "Query failed: %s\n", mysql_error(conn));
} else {
MYSQL_RES *result = mysql_store_result(conn); // 緩衝全量結果集
// 或 mysql_use_result(conn) 逐行流式讀取 (不緩衝、佔用連接)
if (!result) {
fprintf(stderr, "Store result failed: %s\n", mysql_error(conn));
} else {
unsigned int num_fields = mysql_num_fields(result);
MYSQL_FIELD *fields = mysql_fetch_fields(result); // 列元數據
// 打印表頭
for (unsigned int i = 0; i < num_fields; i++) {
printf("%-20s", fields[i].name);
}
printf("\n");
// 遍歷行
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
unsigned long *lengths = mysql_fetch_lengths(result);
for (unsigned int i = 0; i < num_fields; i++) {
printf("%-20.*s", (int)lengths[i], row[i] ? row[i] : "NULL");
}
printf("\n");
}
printf("Total rows: %llu\n", (unsigned long long)mysql_num_rows(result));
mysql_free_result(result); // 必須釋放
}
}
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const char *psql = "INSERT INTO users (name, email) VALUES (?, ?)";
if (mysql_stmt_prepare(stmt, psql, strlen(psql))) {
fprintf(stderr, "Prepare failed: %s\n", mysql_stmt_error(stmt));
} else {
// 綁定參數
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
char name[50], email[100];
unsigned long name_len, email_len;
bind[0].buffer_type = MYSQL_TYPE_VAR_STRING;
bind[0].buffer = name;
bind[0].buffer_length = sizeof(name);
bind[0].length = &name_len;
bind[0].is_null = 0;
bind[1].buffer_type = MYSQL_TYPE_VAR_STRING;
bind[1].buffer = email;
bind[1].buffer_length = sizeof(email);
bind[1].length = &email_len;
bind[1].is_null = 0;
mysql_stmt_bind_param(stmt, bind);
// 批量執行
for (int i = 1; i <= 100; i++) {
snprintf(name, sizeof(name), "User_%d", i);
snprintf(email, sizeof(email), "user%d@example.com", i);
name_len = strlen(name);
email_len = strlen(email);
if (mysql_stmt_execute(stmt)) {
fprintf(stderr, "Execute failed: %s\n", mysql_stmt_error(stmt));
break;
}
}
printf("Batch inserted: %llu rows\n", (unsigned long long)mysql_stmt_affected_rows(stmt));
mysql_stmt_close(stmt);
}
// 關閉自動提交
mysql_autocommit(conn, 0);
mysql_query(conn, "INSERT INTO accounts (user_id, amount) VALUES (1, -100)");
mysql_query(conn, "INSERT INTO accounts (user_id, amount) VALUES (2, 100)");
// 模擬錯誤判斷
if (/* error condition */) {
mysql_rollback(conn);
printf("Transaction rolled back\n");
} else {
mysql_commit(conn);
printf("Transaction committed\n");
}
// 恢復自動提交
mysql_autocommit(conn, 1);
// 封裝宏
#define CHECK_MYSQL(conn, expr) \
do { \
if (expr) { \
fprintf(stderr, "MySQL Error [%s:%d]: %s (Code: %d)\n", \
__FILE__, __LINE__, mysql_error(conn), mysql_errno(conn)); \
exit(1); \
} \
} while(0)
// 使用
CHECK_MYSQL(conn, mysql_real_connect(...));
CHECK_MYSQL(conn, mysql_query(conn, sql));
CHECK_MYSQL(conn, mysql_stmt_prepare(stmt, ...));
mysql_free_result(result);
mysql_stmt_close(stmt);
mysql_close(conn); // 關閉連接並釋放 MYSQL 結構
mysql_library_end(); // 程序退出前調用 (釋放全局庫資源)
C 語言操作 MySQL 核心路徑:
mysql_init → mysql_options → mysql_real_connect → (mysql_query / mysql_stmt_prepare) → 結果處理 → 釋放資源 → mysql_close。
關鍵要點:預處理防注入、緩衝/流式結果集選擇、事務邊界控制、錯誤代碼檢查、嚴格資源釋放。掌握 C API 後,對高級語言驅動 (PDO、SQLAlchemy、GORM、MyBatis) 的底層行為將有透徹理解。