SQLiteCpp入门指南:如何用现代C++快速驾驭SQLite3数据库
【免费下载链接】SQLiteCppSQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper.项目地址: https://gitcode.com/gh_mirrors/sq/SQLiteCpp
你是不是也曾在项目里被 SQLite 的原生 C API 折磨过?打开数据库要sqlite3_open,执行语句要sqlite3_prepare_v2,绑参数要sqlite3_bind_text,每走一步还得手动检查返回值是不是SQLITE_OK……写业务逻辑的时间,全耗在跟底层 API 较劲上了。SQLiteCpp 就是来解决这个痛点的——它是一个轻量级的 C++11 SQLite3 封装库,把底层 C 接口包成几个直观的类,让数据库操作回归到"写业务"本身。
它是来帮你解决问题的,不是来凑热闹的
先别急着背 API,我们换个思路:SQLiteCpp 到底在什么场景下真正值得用?
- 你的项目想用 SQLite,但不想跟 C 接口纠缠:封装之后,建表、查询、插入都只是几行普通 C++ 代码。
- 你受够了手动管理资源:
sqlite3_finalize忘调、连接忘关、异常路径资源泄漏……这些在 SQLiteCpp 里基本绝迹,因为整个库建立在 RAII 之上。你可以把 RAII 想象成酒店房间:入住时自动开锁,退房时自动锁门,哪怕中途出了岔子(抛出异常),门也不会被落下。 - 你希望代码既安全又好看:预处理语句天然防 SQL 注入,异常机制把错误信息带得明明白白,不用再靠
if (rc != SQLITE_OK)的瀑布流撑场面。
简单说,凡是"C++ + SQLite3"的组合,SQLiteCpp 都能让你写得更快、更稳、更体面。它只依赖 C++11 STL 和 SQLite3 本身,MIT 协议,商用无压力,跨 Linux / Windows / macOS 三平台——是个很省心的选择。
十分钟跑起来:安装与最小可运行示例
第一步:把源码拿到手
克隆仓库(内含 sqlite3 与 googletest 子模块,记得同步一下):
git clone https://gitcode.com/gh_mirrors/sq/SQLiteCpp cd SQLiteCpp git submodule init git submodule update第二步:接入你的 CMake 工程
在项目根 CMakeLists.txt 里加上这一小段,把 SQLiteCpp 当子目录引入即可:
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/thirdparty/SQLiteCpp) add_executable(my_app src/main.cpp) target_link_libraries(my_app SQLiteCpp sqlite3 pthread dl )第三步:写下第一个能跑的代码
#include <SQLiteCpp/SQLiteCpp.h> #include <iostream> int main() { try { // 以“可读写 + 不存在则创建”的方式打开数据库 SQLite::Database db("demo.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"); std::cout << "数据库已就绪" << std::endl; } catch (const std::exception& e) { std::cerr << "出错啦:" << e.what() << std::endl; } return 0; }看到没有?打开、建表、捕获错误,三个动作一气呵成。db.exec()负责执行不带返回结果的 SQL,出错时直接抛异常,省去一整套返回值检查。
边做边学:用一个小记账本吃透核心 API
光看片段没感觉,我们直接做一个"个人记账本"小工具,把 SQLiteCpp 的常用招数一路练过去。
建库建表:两行代码搞定
SQLite::Database db("book.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS bills (id INTEGER PRIMARY KEY, title TEXT, amount REAL, kind TEXT)");插入与直查:最朴素的用法
// 记一笔账 db.exec("INSERT INTO bills (title, amount, kind) VALUES ('早餐', 12.5, '餐饮')"); // 想知道表里有多少条记录?execAndGet 直接取单个值 int total = db.execAndGet("SELECT COUNT(*) FROM bills").getInt(); std::cout << "共记了 " << total << " 笔" << std::endl;execAndGet是个很贴心的小工具,专治"取一个值"这种高频需求。
查询的正确姿势:预处理语句 + 参数绑定
直接拼 SQL 字符串既丑又危险(还记得 SQL 注入吗?),预处理语句才是王道:
SQLite::Statement query(db, "SELECT * FROM bills WHERE kind = ?"); query.bind(1, "餐饮"); // 第 1 个 ? 绑定为 "餐饮" while (query.executeStep()) // 每次前进一行 { int id = query.getColumn(0); // 自动转换成 int std::string title = query.getColumn(1); // 自动转换成 string double amount = query.getColumn(2); // 自动转换成 double std::cout << id << " | " << title << " | " << amount << std::endl; }注意到getColumn(0)直接赋给int、std::string、double了吗?这就是 SQLiteCpp 的自动类型转换魔法,读取结果跟用普通变量一样自然。
参数也可以按名字绑定,语义更清晰:
SQLite::Statement query(db, "SELECT * FROM bills WHERE amount > :min_amount"); query.bind(":min_amount", 10.0);更新与删除:别忘了返回值
db.exec("UPDATE bills SET amount = 13.0 WHERE id = 1"); // 返回受影响的行数,方便你确认到底删没删掉 int removed = db.exec("DELETE FROM bills WHERE id = 2"); std::cout << "删除了 " << removed << " 行" << std::endl;事务保护:让批量操作不再心惊胆战
记账时经常要"一次改多行",比如转账:扣 A 的钱、加 B 的钱。如果第一句成功、第二句失败,钱就凭空消失了——所以必须用事务包起来。
try { SQLite::Transaction transaction(db); // 构造即开启事务 db.exec("UPDATE bills SET amount = amount - 100 WHERE id = 1"); db.exec("UPDATE bills SET amount = amount + 100 WHERE id = 2"); transaction.commit(); // 全部成功才提交 } catch (const std::exception& e) { // 只要有任何一步抛异常,析构函数会自动回滚 std::cerr << "事务失败,已自动回滚:" << e.what() << std::endl; }这就是 RAII 事务的妙处:提交是你主动调的,回滚是系统兜底的。就算代码中间抛出异常,数据库也不会留下半截数据。顺带一提,批量写数据时套上事务,性能也能肉眼可见地提升,因为磁盘写入被合并了。
进阶技巧:把 SQLiteCpp 用出花来
1. 变参绑定,一行塞进全部参数
C++14 及以上可以少写好几行 bind:
#include <SQLiteCpp/VariadicBind.h> SQLite::Statement query(db, "INSERT INTO bills (title, amount, kind) VALUES (?, ?, ?)"); SQLite::bind(query, "电影票", 45.0, "娱乐"); query.exec();2. 存二进制数据(BLOB)
存图片、文件都不在话下:
std::vector<char> data = readFile("photo.jpg"); SQLite::Statement insert(db, "INSERT INTO images (data) VALUES (?)"); insert.bind(1, data.data(), static_cast<int>(data.size())); insert.exec();读回来时用getBlob()拿指针、getBytes()拿长度,一对儿配合使用。
3. 纯内存数据库,测试利器
把文件名换成":memory:",数据库就只活在内存里,跑单元测试再合适不过:
SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);4. 从异常里挖出错误码
SQLite::Exception继承自std::runtime_error,除了what()还能拿到数字错误码,方便精确处理:
catch (const SQLite::Exception& e) { std::cerr << e.what() << "(错误码 " << e.getErrorCode() << ")" << std::endl; }5. 查一下版本,心里有底
std::cout << "运行库版本:" << SQLite::getLibVersion() << std::endl; std::cout << "编译时版本:" << SQLite::VERSION << std::endl;常见坑与规避方法:提前帮你排雷
坑一:execAndGet的结果要立刻拷贝。它返回的临时对象很快就会被销毁,别贪图方便把它引用住,直接赋给一个变量是最稳妥的。
// 正确做法:马上拷贝到 string std::string name = db.execAndGet("SELECT name FROM users WHERE id = 1").getText();坑二:默认打开方式是只读。直接SQLite::Database db("x.db3")默认是OPEN_READONLY,想建库建表,记得显式带上OPEN_READWRITE | OPEN_CREATE,不然会收到一个"打不开"的异常,百思不得其解。
坑三:一个连接别跨线程。SQLiteCpp 遵循 SQLite 的"多线程"模式:不同线程可以用不同连接,但同一个 Database 连接不能同时在多个线程里用。多线程场景下给每个线程开自己的连接即可。
坑四:析构函数里只断言、不抛异常。这是设计使然——析构函数抛异常是灾难。如果想让断言更友好(打印信息而不是直接崩),定义SQLITECPP_ENABLE_ASSERT_HANDLER宏并提供自定义断言处理函数即可。
坑五:列元数据需要编译期开关。想用getColumnOriginName()拿到列在原始表里的名字,需要SQLITE_ENABLE_COLUMN_METADATA宏在编译 SQLite 库本身时也开启,否则只能拿到别名。
源码地图:跟着目录找到你要的东西
想深入源码学习,这份地图可以帮你少走弯路:
include/SQLiteCpp/:全部头文件,Database.h(连接)、Statement.h(预处理语句)、Column.h(列访问)、Transaction.h(事务)、Exception.h(异常),还有Backup.h、Savepoint.h、VariadicBind.h、ExecuteMany.h等进阶组件src/:各类的实现源码,注释相当详尽examples/example1/main.cpp:一个文件串起 7 个场景,从读头部信息到 BLOB 存取应有尽有,强烈建议跑一遍tests/:与头文件一一对应的单元测试,想知道某个 API 的边界行为,翻测试最快sqlite3/:内置的 SQLite 源码,不想装系统库时直接编这个
自己动手构建并跑通测试
mkdir build && cd build cmake -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON .. cmake --build . ctest --output-on-failure喜欢 Meson 的话也支持:
meson setup builddir -DSQLITECPP_BUILD_TESTS=true -DSQLITECPP_BUILD_EXAMPLES=true meson compile -C builddir写在最后
这一趟走下来,你已经掌握了 SQLiteCpp 的主干用法:打开连接、建表、预处理查询、参数绑定、事务回滚,还排掉了几个新手必踩的坑。它也许不是最花哨的 C++ SQLite 封装,但那份"简单、安全、像写普通 C++ 一样写数据库"的踏实感,正是它最迷人的地方。
接下来怎么走?建议把examples/example1/main.cpp完整跑一遍,再挑tests/里你感兴趣的测试读一读——动手写两行,比看十页文档都管用。把你的第一个数据库应用做出来,你会发现:原来在 C++ 里跟 SQLite 打交道,也可以这么轻松愉快。💪
【免费下载链接】SQLiteCppSQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper.项目地址: https://gitcode.com/gh_mirrors/sq/SQLiteCpp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考