萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

VC++ 實現 MySQL 資料庫封裝類:基於 C API 的 CDatabase 設計與應用

MySQL 兩大介面架構對比

維度ODBC APIC API (libmysql)
通用性高,支援異構資料庫低,綁定 MySQL
功能完整性標準子集,無法使用 MySQL 專有功能100% 暴露 MySQL 所有能力
效能經 ODBC 管理器轉換,有開銷原生協定,零中間層,效能最優
部署需系統配置 DSN,依賴驅動程式僅需 libmysql.dll 隨程式分發
適用場景多資料庫支援、現有 ODBC 代碼遷移MySQL 專用高效能應用、嵌入式、系統工具

C API 核心資料結構

  • MYSQL:連線控制結構體 (句柄),含連線參數、狀態、緩衝區、協定資訊。
  • MYSQL_RES:結果集結構,含欄位定義、資料行緩衝、游標位置。
  • MYSQL_ROW:單行資料指標陣列 (char**),row[i] 對應第 i 欄位 (0-based)。
  • MYSQL_FIELD:欄位中繼資料 (名稱、類型、長度、旗標、精度)。
  • my_ulonglong:64 位無符號整數,用於影響行數、插入 ID。

C API 關鍵函數流程

MYSQL *conn = mysql_init(NULL);                    // 1. 初始化連線控制結構
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4"); // 設定字元集 (mysql_real_connect 前)
mysql_real_connect(conn, "host", "user", "pass", "db", 3306, NULL, 0); // 2. 建立連線
mysql_query(conn, "SET NAMES utf8mb4");            // 3. 設定連線字元集 (關鍵)
mysql_query(conn, "SELECT * FROM users");          // 4. 發送 SQL
MYSQL_RES *res = mysql_store_result(conn);         // 5. 讀取完整結果集至客戶端緩衝
// 或 mysql_use_result(conn) 串流讀取 (大結果集)
while (MYSQL_ROW row = mysql_fetch_row(res)) {     // 6. 逐行取值
    // row[0] ... row[mysql_num_fields(res)-1]
}
mysql_free_result(res);                            // 7. 釋放結果集
mysql_close(conn);                                 // 8. 關閉連線

CDatabase 封裝類設計 (MFC 風格)

類別定義節錄

class CDatabase {
public:
    // 連線管理
    BOOL ConnectDB(Database_Param* p);             // 參數結構體含 host/user/pass/db/port/charset
    int Reload();                                  // 重連 (斷線重連邏輯)
    virtual ~CDatabase();                          // 解構自動 mysql_close

    // 基礎 CRUD
    BOOL SelectRecord(Data_Param* para);           // 查詢單筆/多筆,結果集內部緩衝
    BOOL InsertRecord(Data_Param* para);           // 參數化構建 INSERT
    BOOL UpdateRecord(Data_Param* para);           // 參數化構建 UPDATE
    BOOL DelRecord(Data_Param* para);              // 參數化構建 DELETE
    BOOL SelectAll(Data_Param* para);              // 全表查詢

    // 結果集游標
    MYSQL_ROW GetRecord();                         // 取得下一行 (內部 mysql_fetch_row)
    BOOL IsEnd();                                  // 判斷是否讀完
    void SeekData(int offset);                     // mysql_data_seek
    unsigned int GetFieldNum();                    // mysql_num_fields
    char* GetFieldName(int index);                 // mysql_fetch_field_direct
    void FreeRecord();                             // mysql_free_result

    // DDL 與管理
    int CreateDB(char* db);                        // CREATE DATABASE
    int DropDB(char* db);                          // DROP DATABASE
    BOOL LockTable(char* table, char* priority);   // LOCK TABLES ... READ/WRITE [LOW_PRIORITY]
    BOOL UnLockTable();                            // UNLOCK TABLES

    // 狀態資訊
    char* GetState();                              // mysql_stat
    char* GetServerInfo();                         // mysql_get_server_info
    int GetProtocolInfo();                         // mysql_get_proto_info
    char* GetHostInfo();                           // mysql_get_host_info
    char* GetClientInfo();                         // mysql_get_client_info
    my_ulonglong GetRowNum();                      // mysql_num_rows / mysql_affected_rows
    char* OutErrors();                             // mysql_error / mysql_errno

private:
    MYSQL mysql;                                   // 連線句柄 (嵌入式,非指針)
    MYSQL_RES* query;                              // 當前結果集
    MYSQL_ROW row;                                 // 當前行
    MYSQL_FIELD* field;                            // 當前欄位
    BOOL FindSave(char* str);                      // 內部:執行查詢並緩存結果集
};

關鍵實現細節

  1. 參數化防注入:Data_Param 結構體承載表名、欄位名、值、條件,內部使用 mysql_real_escape_string 轉義,或升級為預處理 MYSQL_STMT (MySQL 4.1+)。
  2. 字元集管控:ConnectDB 內強制 mysql_options(..., MYSQL_SET_CHARSET_NAME, "utf8mb4") 並 SET NAMES utf8mb4,杜絕亂碼。
  3. 錯誤處理:所有 API 呼叫檢查回傳值,失敗時 OutErrors() 回傳 mysql_error(&mysql),上層決定重試/記錄/拋出異常。
  4. 資源管理:建構子 mysql_init(&mysql),解構子 mysql_close(&mysql)、mysql_free_result(query),符合 RAII。
  5. 斷線重連:Reload() 封裝 mysql_ping 失敗後重新 mysql_real_connect,業務層捕獲 CR_SERVER_GONE_ERROR (2006) / CR_SERVER_LOST (2013) 觸發重連。

應用層調用範例

CDatabase db;
Database_Param param = {"192.168.1.100", "app_user", "StrongPass", "myapp_db", 3306, "utf8mb4"};
if (!db.ConnectDB(¶m)) {
    AfxMessageBox(db.OutErrors());
    return;
}

Data_Param qp = {"users", "id,username,email", "status=1", "id DESC", 0, 20};
if (db.SelectRecord(&qp)) {
    while (!db.IsEnd()) {
        MYSQL_ROW row = db.GetRecord();
        CString id = row[0] ? row[0] : _T("");
        CString name = row[1] ? row[1] : _T("");
        CString email = row[2] ? row[2] : _T("");
        // 綁定 UI 控制項...
    }
    db.FreeRecord();
}
db.~CDatabase(); // 或離開作用域自動調用

進階擴充方向

  • 支援 MYSQL_STMT 預處理:mysql_stmt_prepare、mysql_stmt_bind_param、mysql_stmt_execute、mysql_stmt_bind_result、mysql_stmt_fetch,徹底防注入、提升重複執行效能。
  • 非同步查詢:mysql_send_query + mysql_read_query_result,配合 select()/epoll 實現高併發非阻塞。
  • 連線池:單例管理多個 CDatabase 實例,GetConnection()/ReleaseConnection(),多執行緒安全。
  • ORM 映射:模板元編程將 MYSQL_ROW 自動映射至 C++ 實體類 (Struct/Class)。
copyright © 萬盛學電腦網 all rights reserved