SQLiteCpp入门到进阶:为什么说它是C++项目里最省心的SQLite3包装器
SQLiteCpp入门到进阶为什么说它是C项目里最省心的SQLite3包装器【免费下载链接】SQLiteCppSQLiteC (SQLiteCpp) is a smart and easy to use C SQLite3 wrapper.项目地址: https://gitcode.com/gh_mirrors/sq/SQLiteCpp深夜十一点你的程序跑起来却死活读不出配置数据——翻遍代码发现又在手写sqlite3_open、sqlite3_prepare_v2、sqlite3_bind_int……那一长串C API光是记住参数顺序就要命更别提每步都要检查返回值、手动释放语句句柄。如果你正在寻找一个让C操作SQLite像写Python一样舒服的方案SQLiteCppSQLiteC就是为你准备的答案。它是一个轻量级的现代C11 SQLite3包装器把原生C API封装成几个直观的类用异常和RAII资源获取即初始化帮你把内存泄漏和忘了关连接这类问题从源头消灭。下面我们不讲教科书直接用一个完整例子把它盘活。从一段能跑的代码开始30行搞定建表、插入、查询#include SQLiteCpp/SQLiteCpp.h #include iostream int main() { try { // 打开数据库不存在则自动创建注意标志位 SQLite::Database db(book.db3, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); // 建表 插入exec() 直接返回受影响行数 db.exec(CREATE TABLE IF NOT EXISTS books (id INTEGER PRIMARY KEY, name TEXT, price REAL)); db.exec(INSERT INTO books (name, price) VALUES (C Primer, 128.0)); // 预处理语句? 是占位符稍后绑定防止SQL注入 SQLite::Statement query(db, SELECT id, name, price FROM books WHERE price ?); query.bind(1, 50.0); // 把 50.0 绑到第1个参数 // 逐行取结果executeStep() 返回 true 表示还有下一行 while (query.executeStep()) { int id query.getColumn(0); // Column 支持隐式转 int std::string name query.getColumn(1); // 也支持转 std::string double price query.getColumn(2); // 以及 double std::cout id / name / price std::endl; } } catch (const std::exception e) { std::cerr 数据库出错了 e.what() std::endl; } return 0; }看到query.getColumn(0)直接赋值给int了吗这就是SQLiteCpp最讨喜的地方——Column对象自带类型转换取值不用再写一串sqlite3_column_int样板代码。编译时链接上SQLiteCpp库上面这段代码就能直接跑通。三个核心类撑起你90%的日常操作理解了整体流程我们来拆解这套API的骨架。所有头文件都在项目的 include/SQLiteCpp/ 目录下核心就三个类。Database你的连接管家构造一个Database对象就等于打开连接析构就自动关闭全程不需要你手动调用close()。SQLite::Database db(data.db3); // 默认只读打开文件不存在会抛异常 SQLite::Database db2(data.db3, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); // 读写自动创建 SQLite::Database mem(:memory:); // 纯内存数据库测试神器它还有几个高频小工具db.tableExists(users); // 判断表是否存在 std::string v db.execAndGet(SELECT name FROM users WHERE id1); // 取单值 db.exec(DELETE FROM logs WHERE id 100); // 执行无返回的语句返回影响行数小贴士execAndGet返回的是一个临时Column对象务必立刻拷贝成std::string或数字类型再使用别把临时对象存起来否则下一行代码它就失效了。Statement防SQL注入的预处理语句凡是带用户输入的地方都请走Statementbind()路线而不是拼字符串。// 位置参数从 1 开始编号 SQLite::Statement ins(db, INSERT INTO users (name, age) VALUES (?, ?)); ins.bind(1, 张三); ins.bind(2, 25); ins.exec(); // 执行返回影响行数 ins.reset(); // 复位可以再绑定新值复用也支持命名参数代码可读性直接拉满SQLite::Statement q(db, SELECT * FROM users WHERE age :minAge AND city city); q.bind(:minAge, 18); q.bind(city, 北京);⚠️注意reset()只复位语句不会清空绑定值。想清空要调用clearBindings()否则下次执行会沿用旧的绑定。Column一行结果里的万用转换器getColumn()拿到的Column对象支持向多种类型隐式转换也可以显式调用int i col.getInt(); // 整数 double d col.getDouble(); // 浮点 std::string s col.getString(); // 文本含BLOB也能安全转正确处理内嵌\0 const void* blob col.getBlob();// 二进制 int bytes col.getBytes(); // 字节数 col.isNull(); // 是否为NULL事务与Savepoint让批量操作既快又稳单条INSERT很慢一万条单条INSERT更慢——每条都要走一遍磁盘同步。把批量写包进事务速度往往能提升一个数量级。SQLiteCpp把事务也做成了RAIItry { SQLite::Transaction tx(db); // 构造即开启事务 for (const auto item : items) { SQLite::Statement ins(db, INSERT INTO orders (sku, qty) VALUES (?, ?)); ins.bind(1, item.sku); ins.bind(2, item.qty); ins.exec(); } tx.commit(); // 手动提交 } catch (const std::exception e) { // 没走到 commit()析构时自动 ROLLBACK数据安然无恙 }技巧事务还支持TransactionBehavior::IMMEDIATE/EXCLUSIVE模式写入频繁的多线程场景下IMMEDIATE能提前拿写锁减少数据库被锁的报错。如果只想回滚到某个中间节点不想推倒整个事务可以用SQLite::Savepoint(db, name)源码见 include/SQLiteCpp/Savepoint.h它支持嵌套适合长流程里的局部失败回退。四个进阶玩法从会用到用得好1. BLOB二进制数据一行绑定std::vectorchar img readFile(photo.jpg); SQLite::Statement ins(db, INSERT INTO images (data) VALUES (?)); ins.bind(1, img.data(), static_castint(img.size())); // 指针 长度 ins.exec();2. 变参绑定C14以上直接起飞头文件 include/SQLiteCpp/VariadicBind.h 提供了SQLite::bind()SQLite::Statement ins(db, INSERT INTO users (name, age, email) VALUES (?, ?, ?)); SQLite::bind(ins, 李四, 30, lisiexample.com); // 一次绑定全部自动按顺序3. 列元数据拿到别名背后的原始列名启用SQLITE_ENABLE_COLUMN_METADATA宏CMake里默认开启后SQLite::Statement q(db, SELECT id AS user_id FROM users); q.getColumnName(0); // 返回别名 user_id q.getColumnOriginName(0); // 返回原始列名 id4. 热备份不停机拷贝数据库include/SQLiteCpp/Backup.h 封装了SQLite的在线备份机制可以在库还在被写入时安全拷贝快照SQLite::Backup backup(destDb, srcDb); // 目标库 - 源库 backup.executeStep(-1); // -1 表示一次拷完所有页怎么把它装进你的项目克隆仓库后直接在CMake里以子目录方式引入仓库地址https://gitcode.com/gh_mirrors/sq/SQLiteCppgit clone https://gitcode.com/gh_mirrors/sq/SQLiteCpp.git cd SQLiteCpp git submodule init git submodule update # 拉取googletest编译测试需要在你自己项目的CMakeLists.txt中add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/thirdparty/SQLiteCpp) add_executable(my_app src/main.cpp) target_link_libraries(my_app SQLiteCpp sqlite3 pthread dl)项目默认会用它自带的 sqlite3/sqlite3.c 源码编译你连SQLite都不用单独装这是最省心的一点。想跑测试和示例mkdir build cd build cmake -DSQLITECPP_BUILD_EXAMPLESON -DSQLITECPP_BUILD_TESTSON .. cmake --build . ctest --output-on-failure如果你喜欢Meson项目也提供了meson.build一条命令就能搞定meson setup builddir -DSQLITECPP_BUILD_TESTStrue -DSQLITECPP_BUILD_EXAMPLEStrue meson compile -C builddir多线程与设计哲学它为什么敢替你管理资源SQLiteCpp全库贯彻一个理念对象要么构造成功、永远有效要么直接抛异常。构造Database失败时根本不会得到对象析构函数里绝不抛异常改用断言这就保证了异常安全。关于多线程官方态度很明确支持SQLite的Multi-thread模式但单个连接不能同时在多个线程里用。也就是说每个线程各开各的连接完全没问题而一个连接要串行化使用得自己加锁。它的头文件里也写明了这一点比如 include/SQLiteCpp/Database.h。想要更保险给每个线程分配独立连接即可。四条最佳实践让项目少踩坑所有数据库操作包进 try-catchSQLiteCpp的错误都以SQLite::Exception继承自std::runtime_error抛出e.what()里就是SQLite的原始错误信息别忽略它。重复执行的SQL一律用Statement建一次语句、反复bind复用比每次db.exec()重新解析SQL快得多。批量写入务必开事务几千条INSERT包一个事务速度差距是数量级的。用户输入永远走bind不拼SQL字符串这是防SQL注入的铁律也顺便帮你规避引号转义的各种奇奇怪怪的问题。常见问题解答Q1编译报错undefined reference to sqlite3_column_origin_name怎么办A说明系统自带的sqlite3库没开SQLITE_ENABLE_COLUMN_METADATA。最省事的办法是开启CMake选项SQLITECPP_INTERNAL_SQLITE用项目内置的sqlite3源码编译。Q2execAndGet返回值为什么必须马上拷贝A它内部临时构造了一个Statement和Column返回的Column在语句析构后就失效了。所以std::string v db.execAndGet(...)这种立即拷贝的写法是对的别把引用存起来。Q3同一个Statement能反复用吗A能。执行完后调reset()复位再重新bind()新值即可。记得reset()不清绑定需要清零时调clearBindings()。Q4支持加密数据库吗A支持接口但需要开启SQLITE_HAS_CODEC选项并链接SQLCipher之类的加密实现库Database上提供了key()/rekey()方法。SQLite官方发行版本身不含加密功能。Q5怎么查看我链接的SQLite版本ASQLite::getLibVersion()拿运行时库版本SQLite::VERSION是编译时头文件版本两个一起打印能帮你快速排查版本不一致问题。写在最后SQLiteCpp不是那种看起来很酷但用起来处处受限的玩具包装器——它刻意保持API与原生SQLite一致bind、executeStep、getColumn让你随时能回忆起源生C接口的语义同时又用现代C的异常和RAII把最烦人的资源管理藏了起来。对你来说它就是少写样板代码、少查返回值、少漏close三个诉求的直接答案。无论你是在写桌面工具、游戏存档、还是嵌入式设备上的配置存储花半小时把 examples/example1/main.cpp 里的七个小例子过一遍SQLiteCpp的基本用法就尽在掌握了。剩下的交给你的想象力就好。【免费下载链接】SQLiteCppSQLiteC (SQLiteCpp) is a smart and easy to use C SQLite3 wrapper.项目地址: https://gitcode.com/gh_mirrors/sq/SQLiteCpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考