Skip to content

SQLite3 — 嵌入式数据库

SQLite3 是世界上部署最广泛的数据库,零配置、单文件、无服务器,适合嵌入式、桌面应用和原型开发。

安装

bash
# Ubuntu
sudo apt install libsqlite3-dev

# vcpkg
vcpkg install sqlite3

# CMake
find_package(SQLite3 REQUIRED)
target_link_libraries(myapp PRIVATE SQLite::SQLite3)

C API 基础

cpp
#include <sqlite3.h>
#include <iostream>
#include <stdexcept>

// RAII 包装
class SQLiteDB {
    sqlite3* db_ = nullptr;

public:
    explicit SQLiteDB(const std::string& path) {
        int rc = sqlite3_open(path.c_str(), &db_);
        if (rc != SQLITE_OK) {
            throw std::runtime_error(sqlite3_errmsg(db_));
        }
        // 性能优化
        exec("PRAGMA journal_mode=WAL");
        exec("PRAGMA synchronous=NORMAL");
        exec("PRAGMA cache_size=10000");
        exec("PRAGMA foreign_keys=ON");
    }

    ~SQLiteDB() { if (db_) sqlite3_close(db_); }

    void exec(const std::string& sql) {
        char* err = nullptr;
        int rc = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &err);
        if (rc != SQLITE_OK) {
            std::string msg = err;
            sqlite3_free(err);
            throw std::runtime_error(msg);
        }
    }

    sqlite3* get() { return db_; }
};

// 预处理语句(防 SQL 注入)
class Statement {
    sqlite3_stmt* stmt_ = nullptr;

public:
    Statement(sqlite3* db, const std::string& sql) {
        int rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt_, nullptr);
        if (rc != SQLITE_OK) throw std::runtime_error(sqlite3_errmsg(db));
    }

    ~Statement() { if (stmt_) sqlite3_finalize(stmt_); }

    // 绑定参数(1-indexed)
    void bind(int idx, int val)         { sqlite3_bind_int(stmt_, idx, val); }
    void bind(int idx, int64_t val)     { sqlite3_bind_int64(stmt_, idx, val); }
    void bind(int idx, double val)      { sqlite3_bind_double(stmt_, idx, val); }
    void bind(int idx, const std::string& val) {
        sqlite3_bind_text(stmt_, idx, val.c_str(), -1, SQLITE_TRANSIENT);
    }
    void bind_null(int idx)             { sqlite3_bind_null(stmt_, idx); }

    // 执行(INSERT/UPDATE/DELETE)
    void execute() {
        int rc = sqlite3_step(stmt_);
        if (rc != SQLITE_DONE) throw std::runtime_error("执行失败");
        sqlite3_reset(stmt_);
    }

    // 查询(SELECT)
    bool step() {
        int rc = sqlite3_step(stmt_);
        if (rc == SQLITE_ROW) return true;
        if (rc == SQLITE_DONE) return false;
        throw std::runtime_error("查询失败");
    }

    int    col_int(int idx)    { return sqlite3_column_int(stmt_, idx); }
    double col_double(int idx) { return sqlite3_column_double(stmt_, idx); }
    std::string col_text(int idx) {
        auto* text = sqlite3_column_text(stmt_, idx);
        return text ? reinterpret_cast<const char*>(text) : "";
    }
    bool col_null(int idx) { return sqlite3_column_type(stmt_, idx) == SQLITE_NULL; }
};

完整 CRUD 示例

cpp
int main() {
    SQLiteDB db("app.db");

    // 建表
    db.exec(R"(
        CREATE TABLE IF NOT EXISTS users (
            id    INTEGER PRIMARY KEY AUTOINCREMENT,
            name  TEXT NOT NULL,
            email TEXT UNIQUE NOT NULL,
            age   INTEGER,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    )");

    // 插入(使用预处理语句,防注入)
    {
        Statement stmt(db.get(),
            "INSERT INTO users (name, email, age) VALUES (?, ?, ?)");
        stmt.bind(1, "Alice");
        stmt.bind(2, "alice@example.com");
        stmt.bind(3, 30);
        stmt.execute();

        stmt.bind(1, "Bob");
        stmt.bind(2, "bob@example.com");
        stmt.bind(3, 25);
        stmt.execute();
    }

    // 查询
    {
        Statement stmt(db.get(),
            "SELECT id, name, email, age FROM users WHERE age > ?");
        stmt.bind(1, 20);

        while (stmt.step()) {
            std::cout << stmt.col_int(0) << " "
                      << stmt.col_text(1) << " "
                      << stmt.col_text(2) << " "
                      << stmt.col_int(3) << "\n";
        }
    }

    // 事务(批量操作必用)
    db.exec("BEGIN TRANSACTION");
    try {
        Statement stmt(db.get(),
            "INSERT INTO users (name, email, age) VALUES (?, ?, ?)");
        for (int i = 0; i < 1000; ++i) {
            stmt.bind(1, "User" + std::to_string(i));
            stmt.bind(2, "user" + std::to_string(i) + "@example.com");
            stmt.bind(3, 20 + i % 50);
            stmt.execute();
        }
        db.exec("COMMIT");
    } catch (...) {
        db.exec("ROLLBACK");
        throw;
    }

    // 更新
    {
        Statement stmt(db.get(), "UPDATE users SET age = ? WHERE name = ?");
        stmt.bind(1, 31);
        stmt.bind(2, "Alice");
        stmt.execute();
    }

    // 删除
    {
        Statement stmt(db.get(), "DELETE FROM users WHERE id = ?");
        stmt.bind(1, 1);
        stmt.execute();
    }
}

现代 C++ 封装(SQLiteCpp)

cpp
// SQLiteCpp 库提供更现代的 C++ API
// https://github.com/SRombauts/SQLiteCpp
#include <SQLiteCpp/SQLiteCpp.h>

SQLite::Database db("app.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);

// 建表
db.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)");

// 插入
SQLite::Statement insert(db, "INSERT INTO users VALUES (?, ?)");
insert.bind(1, 1);
insert.bind(2, "Alice");
insert.exec();

// 查询
SQLite::Statement query(db, "SELECT * FROM users WHERE id > ?");
query.bind(1, 0);
while (query.executeStep()) {
    int id = query.getColumn(0);
    std::string name = query.getColumn(1);
    std::cout << id << ": " << name << "\n";
}

// 事务
{
    SQLite::Transaction tx(db);
    // ... 批量操作
    tx.commit();
}

性能调优

sql
-- WAL 模式:读写并发,推荐
PRAGMA journal_mode=WAL;

-- 同步模式:NORMAL 比 FULL 快,安全性略低
PRAGMA synchronous=NORMAL;

-- 内存缓存(页数,每页 4KB)
PRAGMA cache_size=10000;  -- 40MB 缓存

-- 内存数据库(最快,重启丢失)
sqlite3_open(":memory:", &db);

-- 批量插入必须用事务!
-- 无事务:~100 次/秒
-- 有事务:~100000 次/秒

关键认知

SQLite3 的性能关键:批量操作必须用事务(无事务每次写都 fsync,慢 1000x);WAL 模式支持读写并发;预处理语句防 SQL 注入且更快。单文件数据库适合嵌入式和桌面应用,不适合高并发写入场景。

系统学习 C++ 生态,深入底层架构