首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

C 語言操作 MySQL 完整指南:連接、執行 SQL、結果集處理、預處理、錯誤處理

     編輯:MySQL 資料庫相關知識

前言

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));

四、執行非查詢語句 (INSERT/UPDATE/DELETE/DDL)

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);  // 必須釋放
    }
}

六、預處理語句 (Prepared Statements) —— 高效、防注入

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) 的底層行為將有透徹理解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved