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

SQLite3 嵌入式開發全流程:從源碼編譯到 C API 核心操作實戰

     編輯:關於C語言

獲取與編譯 SQLite3 源碼 (Amalgamation)

SQLite 官方提供「合併版」單文件源碼,極易集成:

# 下載最新版 (示例版本號)
wget https://www.sqlite.org/2024/sqlite-amalgamation-3450100.zip
unzip sqlite-amalgamation-3450100.zip
cd sqlite-amalgamation-3450100

# 編譯為靜態庫
gcc -c -O2 -DSQLITE_THREADSAFE=1 -DSQLITE_ENABLE_FTS5=1 sqlite3.c -o sqlite3.o
ar rcs libsqlite3.a sqlite3.o

# 或直接編譯進項目
gcc -O2 main.c sqlite3.c -lpthread -ldl -o myapp

關鍵編譯宏:

宏作用推薦
SQLITE_THREADSAFE=1啟用線程安全 (序列化模式)✅ 生產環境必開
SQLITE_DEFAULT_MEMSTATUS=0關閉內存統計,微量提速嵌入式設備
SQLITE_ENABLE_FTS5全文搜索擴展按需
SQLITE_MAX_MMAP_SIZE=0禁用 mmap (某些嵌入式 FS 不支持)嵌入式
SQLITE_OMIT_DEPRECATED移除棄用 API,減小體積精簡構建

核心 C API 操作流程

sqlite3_open() → sqlite3_prepare_v2() → sqlite3_step() → sqlite3_column_*() → sqlite3_finalize() → sqlite3_close()

1. 打開/創建數據庫

sqlite3 *db;
int rc = sqlite3_open("mydb.sqlite", &db); // 文件不存在則創建
if (rc != SQLITE_OK) {
    fprintf(stderr, "Open failed: %s\n", sqlite3_errmsg(db));
    return rc;
}
// 可選:啟用 WAL 模式提高併發
sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL);

2. 執行無結果集 SQL (DDL/DML)

char *errmsg = NULL;
rc = sqlite3_exec(db,
    "CREATE TABLE IF NOT EXISTS users ("
    "  id INTEGER PRIMARY KEY AUTOINCREMENT,"
    "  name TEXT NOT NULL,"
    "  email TEXT UNIQUE"
    ");",
    NULL, NULL, &errmsg);
if (rc != SQLITE_OK) {
    fprintf(stderr, "Exec failed: %s\n", errmsg);
    sqlite3_free(errmsg);
}

3. 參數化查詢 (防注入、效能複用) — 核心最佳實踐

sqlite3_stmt *stmt;
const char *sql = "INSERT INTO users (name, email) VALUES (?, ?);";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) { /* handle error */ }

// 綁定參數
sqlite3_bind_text(stmt, 1, "Alice", -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, "alice@example.com", -1, SQLITE_TRANSIENT);

// 執行
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) { /* handle error */ }
sqlite3_reset(stmt); // 重置狀態,可重複綁定執行

// 批量插入示例
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
for (int i = 0; i < 1000; ++i) {
    char name[32], email[64];
    sprintf(name, "User%d", i);
    sprintf(email, "user%d@test.com", i);
    sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, email, -1, SQLITE_TRANSIENT);
    sqlite3_step(stmt);
    sqlite3_reset(stmt);
}
sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
sqlite3_finalize(stmt); // 釋放預編譯語句資源

4. 查詢結果集處理

const char *qsql = "SELECT id, name, email FROM users WHERE id > ?;";
sqlite3_stmt *qstmt;
sqlite3_prepare_v2(db, qsql, -1, &qstmt, NULL);
sqlite3_bind_int(qstmt, 1, 10);

while ((rc = sqlite3_step(qstmt)) == SQLITE_ROW) {
    int id = sqlite3_column_int(qstmt, 0);
    const unsigned char *name = sqlite3_column_text(qstmt, 1);
    const unsigned char *email = sqlite3_column_text(qstmt, 2);
    printf("ID: %d, Name: %s, Email: %s\n", id, name, email);
}
if (rc != SQLITE_DONE) { /* error */ }
sqlite3_finalize(qstmt);

5. 回調函數式查詢 (sqlite3_exec 便捷方式)

int callback(void *ctx, int argc, char **argv, char **colNames) {
    for (int i = 0; i < argc; ++i)
        printf("%s = %s\n", colNames[i], argv[i] ? argv[i] : "NULL");
    puts("---");
    return 0; // 非 0 終止查詢
}

sqlite3_exec(db, "SELECT * FROM users;", callback, NULL, &errmsg);

進階主題

事務控制

  • 默認自動提交 (每條 SQL 隱式事務)。
  • 批量寫入**必須**顯式 BEGIN; ... COMMIT;,否則極慢 (每次 fsync)。
  • PRAGMA synchronous=NORMAL/OFF 可權衡安全與速度 (掉電風險)。

WAL 模式 (Write-Ahead Logging)

sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL);
// 優點:讀寫不阻塞、崩潰恢復快、併發高
// 缺點:額外 -wal/-shm 文件、不支持網絡文件系統 (NFS/SMB)

內存數據庫

sqlite3_open(":memory:", &db); // 純內存,進程結束消失
// 或共享內存數據庫
sqlite3_open("file::memory:?cache=shared", &db); // URI 格式,多連接共享

用戶自定義函數

void my_upper(sqlite3_context *ctx, int argc, sqlite3_value **argv) {
    const char *s = (const char *)sqlite3_value_text(argv[0]);
    char *upper = strdup(s);
    for (char *p = upper; *p; ++p) *p = toupper(*p);
    sqlite3_result_text(ctx, upper, -1, free); // free 由 SQLite 調用釋放
}
sqlite3_create_function(db, "my_upper", 1, SQLITE_UTF8, NULL, my_upper, NULL, NULL);
// SQL 中使用: SELECT my_upper(name) FROM users;

錯誤處理與資源管理模板

#define SQLITE_CHECK(rc, db, label) \
    do { if ((rc) != SQLITE_OK) { \
        fprintf(stderr, "SQLite error %d at %s:%d: %s\n", \
                rc, __FILE__, __LINE__, sqlite3_errmsg(db)); \
        goto label; \
    } } while(0)

int do_work() {
    sqlite3 *db = NULL;
    sqlite3_stmt *stmt = NULL;
    int rc;

    rc = sqlite3_open("app.db", &db);
    SQLITE_CHECK(rc, db, err_db);

    rc = sqlite3_prepare_v2(db, "SELECT 1", -1, &stmt, NULL);
    SQLITE_CHECK(rc, db, err_stmt);

    // ... use stmt ...

err_stmt:
    sqlite3_finalize(stmt);
err_db:
    sqlite3_close(db);
    return rc;
}

構建系統集成

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(MyApp)

# 方式 1: 系統庫
find_package(SQLite3 REQUIRED)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE SQLite::SQLite3)

# 方式 2: 嵌入源碼 (推薦嵌入式/靜態鏈接)
add_library(sqlite3 STATIC third_party/sqlite3.c)
target_compile_definitions(sqlite3 PRIVATE
    SQLITE_THREADSAFE=1
    SQLITE_ENABLE_FTS5=1
)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE sqlite3 pthread dl)

總結

SQLite3 以零配置、單文件、ACID 事務、完整 SQL 支持、極小體積 成為嵌入式存儲王者。掌握參數化預編譯語句 (sqlite3_prepare_v2/bind/step/finalize)、顯式事務批量寫入、WAL 模式併發優化、錯誤碼檢查與資源 RAII 管理,即可在 C/C++ 項目中高效、安全地使用 SQLite。建議項目直接嵌入 sqlite3.c 靜態編譯,避免系統庫版本不匹配、編譯選項差異導致的隱性 Bug。

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