MySQL 兩大介面架構對比
| 維度 | ODBC API | C 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); // 內部:執行查詢並緩存結果集
};
關鍵實現細節
- 參數化防注入:
Data_Param 結構體承載表名、欄位名、值、條件,內部使用 mysql_real_escape_string 轉義,或升級為預處理 MYSQL_STMT (MySQL 4.1+)。
- 字元集管控:
ConnectDB 內強制 mysql_options(..., MYSQL_SET_CHARSET_NAME, "utf8mb4") 並 SET NAMES utf8mb4,杜絕亂碼。
- 錯誤處理:所有 API 呼叫檢查回傳值,失敗時
OutErrors() 回傳 mysql_error(&mysql),上層決定重試/記錄/拋出異常。
- 資源管理:建構子
mysql_init(&mysql),解構子 mysql_close(&mysql)、mysql_free_result(query),符合 RAII。
- 斷線重連:
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)。