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

MySQL C API 輕量級 C++ 封裝:Prepared Statement 導向的資料綁定實作

     編輯:MySQL 資料庫相關知識

設計目標

提供型別安全、資源自動管理 (RAII) 的 C++ 薄封裝層,專注於 Prepared Statement (預處理語句) 的參數綁定與結果集映射至 C++ 結構體,減少樣板碼與錯誤處理負擔。

核心類別架構

// 連線參數結構
struct MySQL_parm {
    std::string host, user, password, database, unixsock;
};

// 連線管理類 (非可複製)
class DBMySQL {
    MYSQL* mysqlPtr_;
    uint32_t errno_;
    // 內部建立 MYSQL_STMT*
    MYSQL_STMT* _createSTMT();
public:
    DBMySQL();                 // mysql_init
    void open(const MySQL_parm&); // mysql_real_connect
    void close();              // mysql_close
    const char* strerr() const;   // mysql_error
    friend class DBSTMT;
};

// Prepared Statement 封裝 (非可複製)
class DBSTMT {
    MYSQL_STMT* stmt_;
public:
    DBSTMT(const char* query, DBMySQL& db); // mysql_stmt_init + prepare
    void execute();                         // 無參數執行
    void execute(MYSQL_BIND* bind);         // 綁定結果集並執行
    void bind(MYSQL_BIND* bind);            // 綁定輸入參數
    int fetch();                            // mysql_stmt_fetch,傳回 0 表成功
    ~DBSTMT();                              // mysql_stmt_close
};

關鍵巨集:宣告式綁定定義

利用巨集簡化 MYSQL_BIND 陣列建立,支援二進位 (字串/Blob) 與整數型別:

#define DECL_BIND(StructName, FieldCount) \
class bind_##StructName : public StructName { \
    MYSQL_BIND _bind[FieldCount]; \
    my_bool _is_null[FieldCount]; \
    unsigned long _length[FieldCount]; \
public: \
    bind_##StructName() { \
        int i = 0; \
        bzero(_bind, sizeof(_bind));

#define BIND_BIN(member, len) \
    _bind[i].buffer_type = MYSQL_TYPE_STRING; \
    _bind[i].buffer = (char*)&(parent::member); \
    _bind[i].buffer_length = len; \
    _bind[i].is_null = _is_null + i; \
    _bind[i].length = _length + i; \
    ++i;

#define BIND_INT(member) \
    _bind[i].buffer_type = MYSQL_TYPE_LONG; \
    _bind[i].buffer = (char*)&(parent::member); \
    _bind[i].buffer_length = 0; \
    _bind[i].is_null = _is_null + i; \
    _bind[i].length = _length + i; \
    ++i;

#define END_BIND(StructName) \
    } \
    operator MYSQL_BIND*() { return _bind; } \
};

實戰範例:帳號表查詢與插入

// 1. 定義資料結構
struct account {
    char user[36];
    unsigned char password[16];
    uint32_t status;
    uint32_t id;
};

// 2. 宣告綁定類別 (4 個欄位)
DECL_BIND(account, 4)
    BIND_BIN(user, 32)
    BIND_BIN(password, 16)
    BIND_INT(status)
    BIND_INT(id)
END_BIND(account)

// 3. 主程式
int main() {
    try {
        DBMySQL db;
        MySQL_parm parm = {"localhost", "root", "test", "testdb", "/var/lib/mysql/mysql.sock"};
        db.open(parm);

        // 查詢
        DBSTMT stmt_q("SELECT user, password, status, id FROM account", db);
        bind_account acc;
        stmt_q.execute(acc);          // 綁定結果集並執行
        while (stmt_q.fetch() == 0) {
            printf("%s %u %u\n", acc.user, acc.status, acc.id);
        }

        // 參數化插入
        DBSTMT stmt_i("INSERT INTO account(user, password, status) VALUES (?, ?, ?)", db);
        stmt_i.bind(acc);             // 綁定輸入參數
        // 設定 acc.user/password/status 後...
        stmt_i.execute();             // 執行插入

    } catch (const char* err) {
        fprintf(stderr, "Error: %s\n", err);
    }
    return 0;
}

優勢總結

  • 型別安全: 結構體成員與 MYSQL_BIND 編譯期對應,避免手動填寫索引錯誤。
  • RAII 資源管理: 建構子獲取資源,解構子自動釋放 (mysql_stmt_close/mysql_close)。
  • 異常處理: 統一拋出 const char* 錯誤訊息,簡化上層捕獲。
  • 零開銷抽象: 僅為 C API 增加薄層封裝,效能損耗可忽略。

適用場景: 嵌入式系統、高效能服務端、需精細控制 Prepared Statement 行為的 C++ 專案。

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