SQLite – C/C++

下面是一份 SQLite 在 C/C++ 中使用的完整实战指南,专为 新加坡开发者(时区 +08)量身定制,涵盖:

  • 编译与链接
  • 基础 CRUD
  • 参数化查询(防注入)
  • 事务、错误处理、回调
  • SG 本地时间处理
  • 性能优化 + WAL 模式

一、环境准备(Linux/macOS/Windows)

1. 安装 SQLite(或直接用源码)

# Ubuntu/Debian
sudo apt install libsqlite3-dev

# macOS (Homebrew)
brew install sqlite

# Windows (MSYS2)
pacman -S mingw-w64-x86_64-sqlite3

2. 源码编译(推荐嵌入式项目)

wget https://www.sqlite.org/2025/sqlite-amalgamation-3460100.zip
unzip sqlite-amalgamation-3460100.zip
# 生成 sqlite3.c 和 sqlite3.h

二、C/C++ 基础 API(核心 10 个函数)

函数作用
sqlite3_open()打开数据库
sqlite3_prepare_v2()编译 SQL
sqlite3_step()执行一步
sqlite3_column_*()读取列值
sqlite3_bind_*()绑定参数
sqlite3_finalize()释放语句
sqlite3_close()关闭数据库
sqlite3_exec()快速执行(带回调)
sqlite3_errmsg()错误信息
sqlite3_changes()影响行数

三、完整示例:用户管理系统(C++)

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

using namespace std;

// 回调函数:打印查询结果
int callback(void* data, int argc, char** argv, char** colName) {
    for (int i = 0; i < argc; ++i) {
        cout << colName[i] << ": " << (argv[i] ? argv[i] : "NULL") << "  ";
    }
    cout << endl;
    return 0;
}

// 获取当前 SG 时间(ISO8601)
string now_sg() {
    time_t t = time(nullptr);
    char buf[64];
    // UTC → SG (+8小时)
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&t));
    return string(buf);
}

int main() {
    sqlite3* db;
    char* errMsg = nullptr;
    int rc;

    // 1. 打开数据库
    rc = sqlite3_open("app.db", &db);
    if (rc) {
        cerr << "打开数据库失败: " << sqlite3_errmsg(db) << endl;
        return 1;
    }

    // 2. 启用 WAL 模式(高并发)
    sqlite3_exec(db, "PRAGMA journal_mode = WAL;", nullptr, nullptr, nullptr);
    sqlite3_exec(db, "PRAGMA foreign_keys = ON;", nullptr, nullptr, nullptr);

    // 3. 创建表
    const char* create_sql = R"(
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            email TEXT UNIQUE,
            created_at TEXT DEFAULT (DATETIME('now', 'localtime'))
        );
        CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
    )";
    sqlite3_exec(db, create_sql, nullptr, nullptr, &errMsg);

    // 4. 插入用户(参数化,防注入)
    const char* insert_sql = "INSERT INTO users (name, email) VALUES (?, ?);";
    sqlite3_stmt* stmt;
    sqlite3_prepare_v2(db, insert_sql, -1, &stmt, nullptr);

    string name = "Alice Tan";
    string email = "alice@example.com";

    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, email.c_str(), -1, SQLITE_TRANSIENT);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        cerr << "插入失败: " << sqlite3_errmsg(db) << endl;
    } else {
        cout << "插入成功,ID: " << sqlite3_last_insert_rowid(db) << endl;
    }

    sqlite3_finalize(stmt);

    // 5. 查询用户
    cout << "\n=== 用户列表 ===\n";
    string query = "SELECT id, name, email, created_at FROM users;";
    sqlite3_exec(db, query.c_str(), callback, nullptr, &errMsg);

    // 6. 事务:批量插入
    sqlite3_exec(db, "BEGIN IMMEDIATE;", nullptr, nullptr, nullptr);
    for (int i = 1; i <= 5; ++i) {
        string n = "User" + to_string(i);
        string e = "user" + to_string(i) + "@test.com";
        sqlite3_prepare_v2(db, insert_sql, -1, &stmt, nullptr);
        sqlite3_bind_text(stmt, 1, n.c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(stmt, 2, e.c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_step(stmt);
        sqlite3_finalize(stmt);
    }
    sqlite3_exec(db, "COMMIT;", nullptr, nullptr, nullptr);

    cout << "\n批量插入完成!\n";

    // 7. 关闭
    sqlite3_close(db);
    return 0;
}

四、SG 时间处理(C++ 实现)

// 插入当前 SG 时间
string sg_time = now_sg();
sqlite3_bind_text(stmt, 3, sg_time.c_str(), -1, SQLITE_TRANSIENT);

// 查询并格式化
const char* time_col = (const char*)sqlite3_column_text(stmt, 3);
cout << "创建时间(SG): " << time_col << endl;

SQLite 自动识别 DATETIME('now', 'localtime')推荐在 SQL 中处理


五、参数化查询(防注入)—— 必须掌握

// 危险:字符串拼接(SQL 注入)
string sql = "SELECT * FROM users WHERE email = '" + user_input + "';";

// 安全:参数化
const char* safe_sql = "SELECT * FROM users WHERE email = ?;";
sqlite3_prepare_v2(db, safe_sql, -1, &stmt, nullptr);
sqlite3_bind_text(stmt, 1, user_input.c_str(), -1, SQLITE_TRANSIENT);

六、错误处理封装(生产级)

class SQLiteDB {
    sqlite3* db;
public:
    SQLiteDB(const string& path) {
        if (sqlite3_open(path.c_str(), &db) != SQLITE_OK) {
            throw runtime_error(sqlite3_errmsg(db));
        }
    }
    ~SQLiteDB() { sqlite3_close(db); }

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

七、性能优化建议

配置C/C++ 设置
WAL 模式PRAGMA journal_mode = WAL;
同步模式PRAGMA synchronous = NORMAL;
页面大小PRAGMA page_size = 4096;
缓存大小PRAGMA cache_size = -20000; (20MB)
编译选项-DSQLITE_THREADSAFE=1
sqlite3_exec(db, "PRAGMA journal_mode = WAL;", nullptr, nullptr, nullptr);
sqlite3_exec(db, "PRAGMA cache_size = -20000;", nullptr, nullptr, nullptr);

八、编译命令

# C++
g++ -std=c++17 main.cpp -lsqlite3 -o app

# C
gcc main.c -lsqlite3 -o app

# 嵌入式(单文件)
gcc sqlite3.c your_app.c -pthread -ldl -o app

九、常见问题(FAQ)

问题解决方案
database is locked使用 BEGIN IMMEDIATE 或 WAL 模式
no such column检查 sqlite3_column_name() 索引
SQL logic error检查 sqlite3_errmsg(db)
内存泄漏每个 prepare 必须 finalize
多线程安全编译 -DSQLITE_THREADSAFE=1,每个线程独立 sqlite3*

十、快速模板(复制即用)

1. 安全插入

void insert_user(sqlite3* db, const string& name, const string& email) {
    const char* sql = "INSERT INTO users (name, email) VALUES (?, ?);";
    sqlite3_stmt* stmt;
    sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, email.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);
}

2. 查询单条

string get_email(sqlite3* db, int id) {
    const char* sql = "SELECT email FROM users WHERE id = ?;";
    sqlite3_stmt* stmt;
    sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
    sqlite3_bind_int(stmt, 1, id);
    if (sqlite3_step(stmt) == SQLITE_ROW) {
        return string((const char*)sqlite3_column_text(stmt, 0));
    }
    sqlite3_finalize(stmt);
    return "";
}

总结:C/C++ + SQLite 最佳实践

项目推荐
防注入必须用 ? + sqlite3_bind_*
时间SQL 中用 DATETIME('now','localtime')
事务批量操作用 BEGIN ... COMMIT
并发开启 WAL 模式
错误处理每次检查返回值
资源释放finalize + close

需要我为你生成:

  • 带登录验证 + 会话管理的完整 C++ 服务
  • 高性能日志系统(百万级/秒)
  • Android NDK SQLite 封装

把你的需求发我,10 分钟出代码!

文章已创建 2326

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部