首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言入門

C語言通用數據庫接口設計:SQLite 封裝、動態構建 SQL 與結果集映射

     編輯:C 語言入門

設計目標

在無反射、無 ORM 的 C 語言中,實現類似 Hibernate 的體驗:結構體 ↔ 表自動映射、CRUD 統一入口、類型安全。

核心數據結構

// 業務實體
typedef struct User {
    int id;
    char *name;
    char *password;
} User;

// 通用鏈表承載查詢結果
typedef struct SelectNode {
    void *value;                 // 指向具體結構體實例
    struct SelectNode *next;
} SelectNode;

typedef void (*ValueFreeFunc)(void *); // 釋放回調

SelectNode *select_list_new(void);
void select_list_free(SelectNode *head, ValueFreeFunc free_fn);

SQL 模板宏


#define SELECT_(cols, table, where)  "SELECT " cols " FROM " #table " WHERE " #where
#define INSERT_(table, cols, vals)   "INSERT INTO " #table " (" cols ") VALUES (" vals ")"
#define UPDATE_(table, set, where)   "UPDATE " #table " SET " set " WHERE " #where
#define DELETE_(table, where)        "DELETE FROM " #table " WHERE " #where

// 變參執行器
#define sql_exec(fmt, ...)  _sql_exec(fmt, __VA_ARGS__)
#define select_tbl(res, fmt, ...) _select_tbl((void**)(res), fmt, __VA_ARGS__)

增刪改統一執行器


int _sql_exec(const char *fmt, ...) {
    char sql[1024];
    va_list ap; va_start(ap, fmt);
    vsnprintf(sql, sizeof(sql), fmt, ap);
    va_end(ap);

    char *err = NULL;
    int rc = sqlite3_exec(db, sql, NULL, NULL, &err);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL錯誤: %s\nSQL: %s\n", err, sql);
        sqlite3_free(err);
    }
    return rc;
}

查詢結果映射核心


// 表名 → 映射函數 的註冊表(簡化版用 if-else)
void *map_user(sqlite3_stmt *stmt) {
    User *u = calloc(1, sizeof(User));
    int cols = sqlite3_column_count(stmt);
    for (int i = 0; i < cols; i++) {
        const char *col = sqlite3_column_name(stmt, i);
        if (strcmp(col, "id") == 0) u->id = sqlite3_column_int(stmt, i);
        else if (strcmp(col, "name") == 0) u->name = strdup((char*)sqlite3_column_text(stmt, i));
        else if (strcmp(col, "password") == 0) u->password = strdup((char*)sqlite3_column_text(stmt, i));
    }
    return u;
}

int _select_tbl(void **result, const char *fmt, ...) {
    char sql[1024];
    va_list ap; va_start(ap, fmt);
    vsnprintf(sql, sizeof(sql), fmt, ap);
    va_end(ap);

    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;

    SelectNode *head = NULL, *tail = NULL;
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        const char *tbl = sqlite3_column_table_name(stmt, 0);
        void *obj = NULL;
        if (strcmp(tbl, "User") == 0) obj = map_user(stmt);
        // else if ... 其他表映射

        if (obj) {
            SelectNode *node = select_list_new();
            node->value = obj;
            if (!head) head = tail = node;
            else { tail->next = node; tail = node; }
        }
    }
    *result = head;
    sqlite3_finalize(stmt);
    return 0;
}

使用示例


// 插入
User u = {0, "alice", "secret"};
sql_exec(INSERT_(User, "id,name,password", "%d,'%s','%s"), u.id, u.name, u.password);

// 查詢
SelectNode *list = NULL;
select_tbl(&list, SELECT_("*", User, "name='alice'"));
for (SelectNode *n = list; n; n = n->next) {
    User *u = n->value;
    printf("%d %s %s\n", u->id, u->name, u->password);
}
select_list_free(list, (ValueFreeFunc)user_free); // 釋放字符串與節點

擴展建議

  • 哈希表註冊映射:unordered_map<string, MapperFunc> 替換 if-else,支援動態加載。
  • 預編譯語句緩存:複用 sqlite3_stmt* 避免重複解析。
  • 事務封裝:BEGIN/COMMIT/ROLLBACK 宏。
  • 連接池:多線程環境下管理 sqlite3* 池。

總結

通過「SQL 模板宏 + 變參執行器 + 表名分發映射函數 + 通用鏈表結果集」,在 C 語言中構建出類型相對安全、語法接近 ORM 的數據庫訪問層,適合中小型嵌入式/桌面項目。

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