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

C++ SQLite 實戰:輕量級嵌入式資料庫完整封裝與應用

     編輯:C++ 入門

為什麼選擇 SQLite

專案需本地持久化結構化數據,字段較多且需靈活查詢。記憶體結構(vector/map)查詢不便,重型資料庫(MySQL/PostgreSQL)部署過於繁瑣。SQLite 作為零配置、單文件、跨平台的嵌入式引擎,完美契合輕量級本地存儲場景。

封裝設計目標

  • RAII 資源管理:構造開啟、析構自動關閉,杜絕洩漏。
  • 統一錯誤處理:封裝 SQLite 返回碼,提供統一錯誤訊息獲取。
  • 支援事務:批量寫入自動包裹事務,提升效能並保證原子性。
  • 回調查詢結果:通用回調函數處理 SELECT 結果集。

核心類別設計


#ifndef SQLITE_HELPER_H
#define SQLITE_HELPER_H

#include <sqlite3.h>
#include <string>

class SQLiteHelper {
public:
    SQLiteHelper() : db_(nullptr), errMsg_(nullptr), isClosed_(true) {}
    ~SQLiteHelper() { close(); }

    // 禁止拷貝,支援移動
    SQLiteHelper(const SQLiteHelper&) = delete;
    SQLiteHelper& operator=(const SQLiteHelper&) = delete;
    SQLiteHelper(SQLiteHelper&& other) noexcept 
        : db_(other.db_), errMsg_(other.errMsg_), isClosed_(other.isClosed_) {
        other.db_ = nullptr; other.errMsg_ = nullptr; other.isClosed_ = true;
    }

    // 核心操作
    bool open(const std::string& path);
    void close();
    bool exec(const std::string& sql);           // 通用執行(DDL/DML)
    bool query(const std::string& sql);          // 查詢並觸發回調顯示
    bool beginTransaction();
    bool commitTransaction();
    bool rollbackTransaction();

    // 便利方法
    bool createTable(const std::string& tableDef);
    bool dropTable(const std::string& tableName);
    bool insert(const std::string& sql);
    bool update(const std::string& sql);
    bool remove(const std::string& sql);

private:
    sqlite3* db_;
    char* errMsg_;
    bool isClosed_;

    static int callback(void* notUsed, int argc, char** argv, char** colName);
    bool execInternal(const char* sql);
};

#endif

關鍵實現細節

資源管理與錯誤處理


bool SQLiteHelper::open(const std::string& path) {
    if (!isClosed_) close();
    int rc = sqlite3_open(path.c_str(), &db_);
    if (rc != SQLITE_OK) {
        std::cerr << "Open DB failed: " << sqlite3_errmsg(db_) << std::endl;
        sqlite3_close(db_);
        db_ = nullptr;
        return false;
    }
    isClosed_ = false;
    return true;
}

void SQLiteHelper::close() {
    if (!isClosed_ && db_) {
        sqlite3_close(db_);
        db_ = nullptr;
        isClosed_ = true;
    }
}

事務支援(批量寫入關鍵)


bool SQLiteHelper::insert(const std::string& sql) {
    if (!beginTransaction()) return false;
    bool ok = execInternal(sql.c_str());
    if (ok) ok = commitTransaction();
    else rollbackTransaction();
    return ok;
}

bool SQLiteHelper::beginTransaction() {
    return execInternal("BEGIN TRANSACTION;");
}
bool SQLiteHelper::commitTransaction() {
    return execInternal("COMMIT TRANSACTION;");
}
bool SQLiteHelper::rollbackTransaction() {
    return execInternal("ROLLBACK TRANSACTION;");
}

通用回調處理查詢結果


int SQLiteHelper::callback(void* notUsed, int argc, char** argv, char** colName) {
    for (int i = 0; i < argc; ++i) {
        std::cout << colName[i] << " = " << (argv[i] ? argv[i] : "NULL") << "\t";
    }
    std::cout << std::endl;
    return 0; // 返回非 0 會中止查詢
}

bool SQLiteHelper::query(const std::string& sql) {
    return execInternal(sql.c_str());
}

bool SQLiteHelper::execInternal(const char* sql) {
    char* errMsg = nullptr;
    int rc = sqlite3_exec(db_, sql, callback, nullptr, &errMsg);
    if (rc != SQLITE_OK) {
        std::cerr << "SQL Error: " << (errMsg ? errMsg : "Unknown") << std::endl;
        sqlite3_free(errMsg);
        return false;
    }
    return true;
}

完整測試案例


#include "sqlite_helper.h"
#include <iostream>
#include <sstream>

int main() {
    SQLiteHelper db;
    if (!db.open("./Test.db3")) return 1;

    // 建表
    if (!db.createTable("test_table (id INT PRIMARY KEY, name TEXT, age INT)")) return 1;

    // 批量插入(事務保護)
    for (int i = 1; i < 10; ++i) {
        std::ostringstream oss;
        oss << "INSERT INTO test_table VALUES (" << i << ", 'Name" << i+10 << "', 23);";
        if (!db.insert(oss.str())) return 1;
    }
    db.query("SELECT * FROM test_table;");

    // 刪除
    db.remove("DELETE FROM test_table WHERE id = 4;");
    db.query("SELECT * FROM test_table;");

    // 更新
    db.update("UPDATE test_table SET name = 'SQLite3' WHERE name = '17';");
    db.query("SELECT * FROM test_table;");

    // 刪表
    db.dropTable("test_table");
    db.query("SELECT * FROM test_table;"); // 將報錯:no such table

    return 0;
}

執行結果截圖

SQLite 測試執行結果

進階優化建議

  • 預編譯語句:高頻 SQL 使用 sqlite3_prepare_v2 + sqlite3_bind,防注入並提速。
  • 連線池:多執行緒場景下維護連線池,避免頻繁開關資料庫。
  • WAL 模式:啟用 PRAGMA journal_mode=WAL; 大幅提升並發讀寫效能。
  • 參數化查詢封裝:提供 queryParams(sql, params...) 介面,自動綁定參數。
  • 異步寫入隊列:高寫入場景下,主線程推入隊列,專用線程批量落庫。

常見坑點提醒

  1. SQLite 無資料類型強制約束,TEXT 列可存數字,應用層需自行驗證。
  2. sqlite3_exec 回調函數中不可再呼叫 sqlite3_exec,會死鎖。
  3. 大量插入必須使用事務,否則每筆預設自動提交,速度差 100 倍以上。
  4. 資料庫檔案鎖定問題:多進程訪問需配置適當超時 sqlite3_busy_timeout。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved