下面是一份 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 分钟出代码!