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 注入且更快。单文件数据库适合嵌入式和桌面应用,不适合高并发写入场景。