SQLite是⼀个开源、轻量级、零配置、⽆服务器、⾃包含、事务性、⽀持标准SQL、跨平台的数据库管理系统。⼀般常用于嵌入式系统、移动开发中。不是很难的业务逻辑用用SQLite也不错~完整示例代码在文末一、安装1. 命令行方式安装sudo apt install sqlite3 # 安装 sqlite3 命令⾏⼯具 sudo apt install libsqlite3-dev # 安装 sqlite 开发包如果想在命令行开发方式1项目里用API开发方式2当然都用也可以KB级别的软件下载时间在半分钟之内~2. 验证是否安装成功检查头文件静态库动态库bearVM-12-17-ubuntu:~/clean_sh$ sudo ls /usr/include/sqlite3.h /usr/include/sqlite3.h bearVM-12-17-ubuntu:~/clean_sh$ sudo ls /usr/lib/x86_64-linux-gnu/libsqlite3.a /usr/lib/x86_64-linux-gnu/libsqlite3.a bearVM-12-17-ubuntu:~/clean_sh$ sudo ls /usr/lib/x86_64-linux-gnu/libsqlite3.so /usr/lib/x86_64-linux-gnu/libsqlite3.so以图为证二、链接编译包括头文件、链接添加 sqlite3 库//makefile⽂件 g main.cpp -o my_program -lsqlite3 //CMakelists.txt target_link_libraries(${SDK_NAME} sqlite3)三、API介绍数据库连接管理 int sqlite3_open(const char *filename, sqlite3 **ppDb); 功能打开⼀个数据库连接。如果数据库⽂件不存在则创建它 参数filename - 数据库⽂件的路径 ppDb⼀个指向sqlite3*的指针。函数成功后会在这个指针⾥填⼊数据库连接句柄 返回值SQLITE_OK 表⽰创建成功否则为错误码 int sqlite3_close(sqlite3* db); 功能关闭打开的数据库连接并释放所有资源 参数要关闭的数据库连接句柄 返回值SQLITE_OK表⽰成功如果还有未完成的预处理语句 const char *sqlite3_errmsg(sqlite3* db); 功能获取与数据库连接相关的最后⼀次错误操作的英⽂描述字符串。在操作失败后调⽤它来获取错误 原因 参数db数据库连接句柄 返回值只想错误信息字符串的指针。如果还有查询没有完成将返回SQLITE_BUSY禁⽌关闭的错误消 息 /////////////////////////////////////////////////////////////// int sqlite3_prepare_v2( sqlite3 *db,const char *zSql,int nByte, sqlite3_stmt **ppStmt,const char **pzTail); 功能将⼀条SQL语句编译成⼀个预处理语句对象为执⾏和绑定参数做准备 参数db - 数据库连接句柄 zSql要编译的SQL语句⽂本 nByteSQL⽂本的⻓度(字节)-1表⽰⾃动计算到\0结束 ppStmt指向sqlite3_stmt*的指针表⽰输出预处理结果语句的句柄 pzTail指向未使⽤的SQL部分指针通常置为NULL 返回值编译成功返回SQLITE_K否则返回错误码 int sqlite3_bind_int64(sqlite3_stmt*, int index, sqlite3_int64 value); 功能向预处理语句中的指定参数位置绑定⼀个64位的整数值 参数index - 参数的序号从1开始 value - 要绑定的整数值 返回值SQLITE_OK表⽰绑定成功否则为错误码 int sqlite3_bind_text(sqlite3_stmt*, int index, const char *value, int len, void(*destructor)(void*)); 功能向预处理语句的指定参数位置绑定⼀个⽂本字符串 参数 index - 参数的序号从1开始 value - 要绑定的⽂本字符串 len - 字符串的⻓度(字节)-1表⽰⾃动计算到\0结束 destructor⽤于指定SQLite不会尝试释放该字符串 SQLITE_STATICSQLite不会尝试释放该字符串 SQLITE_TRANSIENTSQLite会制作该字符串的副本 返回值SQLITE_OK表⽰绑定成功否则为错误码 int sqlite3_exec(sqlite3* db, const char *sql,int (*callback)(void*, int, char**, char**),void *arg,char **errmsg); 功能执⾏⼀条或多条SQL语句适合不返回数据的语句如CREATE、INSERT 参数db - 数据库连接句柄 sql - 要执⾏的SQL语句字符串 callback回调函数每有⼀条结果记录就产⽣⼀次调⽤可以设置为NULL arg传递给回调函数的第⼀个参数 errmsg只想错误信息的指针。必须⽤sqlite3_free释放 返回值执⾏成功返回SQLITE_OK否则返回错误码 int sqlite3_step(sqlite3_stmt *pStmt); 功能⽤于逐步执⾏预处理语句。⼀般⽤于执⾏查询和更新操作并返回执⾏结果。对于查询操作 sqlite3_step 需要多次调⽤直到返回 SQLITE_DONE 参数pstmt - 预处理语句句柄 返回值 SQLITE_ROW - 表⽰有⼀⾏结果数据就绪 SQLITE_DONE - 表⽰语句执⾏完成 否则表⽰有其他错误 const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); 功能从当前结果⾏中以const unsigned cht*的形式获取制定⽂本列的值 参数iCol表⽰列号从0开始 返回值指向⽂本数据的指针。 int sqlite3_finalize(sqlite3_stmt *pStmt); 功能销毁预处理语句对象释放所有关联资源 参数pstmt - 要销毁的预处理语句句柄 返回值成功返回SQLITE_OK否则为错误码四、快速上手教程--用户信息管理本次实战围绕用户信息管理展开核心需求如下覆盖SQLite最常用的基础操作适合新手入门创建/打开SQLite数据库文件若数据库不存在则自动创建初始化数据库创建「user」表包含id、name、age三个字段id为主键实现用户信息插入支持传入用户对象插入name和age字段实现用户信息查询查询所有用户、根据用户名查询单个用户规范资源释放避免内存泄漏和数据库连接异常。需求核心用C封装数据库操作类简化SQLite调用流程同时掌握核心接口的使用规范和易错点#include sqlite3.h #include iostream #include string // 用户数据结构对应数据库中的user表 struct User { int id; // 主键插入时可忽略SQLite自动自增 std::string name; // 用户名非空 int age; // 年龄非空 // 默认构造函数用于查询失败时返回空对象 User() : id(0), name(), age(0) {} // 带参构造函数用于查询成功时返回用户对象 User(int _id, std::string _name, int _age) : id(_id), name(_name), age(_age) {} };接下来就是快速上手流程按照顺序来实现方便熟悉接口且逻辑流畅~1. 数据库创建/打开 析构class UserDB { public: UserDB(const std::string dbName) : _db(nullptr) { // op1:创建/打开数据库 if (SQLITE_OK ! sqlite3_open(dbName.c_str(), _db)) { std::cout 数据库打开/创建失败 sqlite3_errmsg(_db) std::endl; return; } // op2:初始化数据库 if (!initUserDB()) { std::cout 数据库初始化失败 std::endl; return; } std::cout 数据库初始化成功 std::endl; } ~UserDB() { if (_db) { sqlite3_close(_db); _db nullptr; }// 判空 释放资源 置空 —— 此乃C开发者的核心素养呐 } private: sqlite3* _db; };initUserDB() ?这并非API而是我们自己封装的逻辑~接下来就是此函数2. 初始化数据库bool initUserDB() { // op1:写sql语句 -- 建表 std::string sql R(create table if not exists user( id integer primary key, name text not null, age integer not null );); // op2:执行sql -- 建表 char* errMsg nullptr; if (SQLITE_OK ! sqlite3_exec(_db, sql.c_str(), nullptr, nullptr, errMsg)) { std::cout 创建表失败 errMsg std::endl; sqlite3_free(errMsg); return false; } return true; }如果你成功创建数据库 初始化数据库接下来就是CURD —— 大名鼎鼎的“增删查改”3. 添加数据项 -- 增加一条数据进数据库bool insertUser(const User user) { // op1:写sql std::string sql insert into user(name,age) values(?,?);; // op2:预处理sql sqlite3_stmt* stmt nullptr; if (SQLITE_OK ! sqlite3_prepare_v2(_db, sql.c_str(), -1, stmt, nullptr)) { std::cout SQL预处理失败 sqlite3_errmsg(_db) std::endl; sqlite3_finalize(stmt); return false; } // op3:绑定参数 sqlite3_bind_text(stmt, 1, user.name.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, user.age); // op4:执行sql if (SQLITE_DONE ! sqlite3_step(stmt)) { std::cout 用户插入失败 sqlite3_errmsg(_db) std::endl; sqlite3_finalize(stmt); return false; } // op5:执行完sql 释放资源 sqlite3_finalize(stmt); std::cout 用户插入成功 std::endl; return true; }到这可以发现sql有两种执行方式傻瓜式exec 手动式preparebindstep对于建表不需要取数据直接无脑exec ; 而插入更新查询删除等操作要不是绑定值或者一行一行取数据判断都是需要step方式4. 查询所有条目bool queryAllUser() { // op1:写sql std::string sql select * from user;; // op2:预处理 sqlite3_stmt* stmt nullptr; if (SQLITE_OK ! sqlite3_prepare_v2(_db, sql.c_str(), -1, stmt, nullptr)) { std::cout SQL预处理失败 sqlite3_errmsg(_db) std::endl; return false; } // op3:执行这里没有参数要绑定 std::cout 所有用户信息 std::endl; while (SQLITE_ROW sqlite3_step(stmt)) { int id sqlite3_column_int(stmt, 0); std::string name reinterpret_castconst char*(sqlite3_column_text(stmt, 1)); int age sqlite3_column_int(stmt, 2); std::cout id id 姓名 name 年龄 age std::endl; } // op4:执行完sql需要释放资源 sqlite3_finalize(stmt); return true; }5. 查询一条数据 -- 通过姓名字段查询User queryUserByName(const std::string name) { // op1:写sql std::string sql select * from user where name ?;; // op2:预处理 sqlite3_stmt* stmt nullptr; if (SQLITE_OK ! sqlite3_prepare_v2(_db, sql.c_str(), -1, stmt, nullptr)) { std::cout SQL预处理失败 sqlite3_errmsg(_db) std::endl; return User(); } // op3:绑定参数 sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT); // op4:执行sql if (SQLITE_ROW sqlite3_step(stmt)) { int id sqlite3_column_int(stmt, 0); std::string userName reinterpret_castconst char*(sqlite3_column_text(stmt, 1)); int age sqlite3_column_int(stmt, 2); // op5.1注意释放 sqlite3_finalize(stmt); return User(id, userName, age); } else { // op5.2注意释放 std::cout 未查询到用户 name std::endl; sqlite3_finalize(stmt); return User(); } }测试代码int main() { // 1. 创建数据库实例数据库文件为user.db位于当前目录 UserDB db(user.db); // 2. 插入测试用户 User user1(0, 张三, 22); // id为0插入时会自动自增 User user2(0, 李四, 25); db.insertUser(user1); db.insertUser(user2); // 3. 查询所有用户 db.queryAllUser(); // 4. 根据用户名查询单个用户 User queryUser db.queryUserByName(张三); if (queryUser.id ! 0) { std::cout 查询到用户id queryUser.id name queryUser.name age queryUser.age std::endl; } return 0; }执行截图相信仔细的同学也发现了作者未写“删除数据的代码”这个不妨留给有心的你~作为检验你上手的炼金石比喻有一点夸张但是练练手也无妨五、完整参考代码#include sqlite3.h #include iostream #include string struct User { int id; std::string name; int age; User() : id(0), name(), age(0) {} User(int _id, std::string _name, int _age) : id(_id), name(_name), age(_age) {} }; class UserDB { public: UserDB(const std::string dbName) : _db(nullptr) { if (SQLITE_OK ! sqlite3_open(dbName.c_str(), _db)) { std::cout 数据库打开/创建失败 sqlite3_errmsg(_db) std::endl; return; } if (!initUserDB()) { std::cout 数据库初始化失败 std::endl; return; } std::cout 数据库初始化成功 std::endl; } ~UserDB() { if (_db) { sqlite3_close(_db); _db nullptr; } } bool insertUser(const User user) { std::string sql insert into user(name,age) values(?,?);; sqlite3_stmt* stmt nullptr; if (SQLITE_OK ! sqlite3_prepare_v2(_db, sql.c_str(), -1, stmt, nullptr)) { std::cout SQL预处理失败 sqlite3_errmsg(_db) std::endl; sqlite3_finalize(stmt); return false; } sqlite3_bind_text(stmt, 1, user.name.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, user.age); if (SQLITE_DONE ! sqlite3_step(stmt)) { std::cout 用户插入失败 sqlite3_errmsg(_db) std::endl; sqlite3_finalize(stmt); return false; } sqlite3_finalize(stmt); std::cout 用户插入成功 std::endl; return true; } bool queryAllUser() { std::string sql select * from user;; sqlite3_stmt* stmt nullptr; if (SQLITE_OK ! sqlite3_prepare_v2(_db, sql.c_str(), -1, stmt, nullptr)) { std::cout SQL预处理失败 sqlite3_errmsg(_db) std::endl; return false; } std::cout 所有用户信息 std::endl; while (SQLITE_ROW sqlite3_step(stmt)) { int id sqlite3_column_int(stmt, 0); std::string name reinterpret_castconst char*(sqlite3_column_text(stmt, 1)); int age sqlite3_column_int(stmt, 2); std::cout id id 姓名 name 年龄 age std::endl; } sqlite3_finalize(stmt); return true; } User queryUserByName(const std::string name) { std::string sql select * from user where name ?;; sqlite3_stmt* stmt nullptr; if (SQLITE_OK ! sqlite3_prepare_v2(_db, sql.c_str(), -1, stmt, nullptr)) { std::cout SQL预处理失败 sqlite3_errmsg(_db) std::endl; return User(); } sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT); if (SQLITE_ROW sqlite3_step(stmt)) { int id sqlite3_column_int(stmt, 0); std::string userName reinterpret_castconst char*(sqlite3_column_text(stmt, 1)); int age sqlite3_column_int(stmt, 2); sqlite3_finalize(stmt); return User(id, userName, age); } else { std::cout 未查询到用户 name std::endl; sqlite3_finalize(stmt); return User(); } } private: bool initUserDB() { std::string sql R(create table if not exists user( id integer primary key, name text not null, age integer not null );); char* errMsg nullptr; if (SQLITE_OK ! sqlite3_exec(_db, sql.c_str(), nullptr, nullptr, errMsg)) { std::cout 创建表失败 errMsg std::endl; sqlite3_free(errMsg); return false; } return true; } private: sqlite3* _db; }; int main() { // 1. 创建数据库实例数据库文件为user.db位于当前目录 UserDB db(user.db); // 2. 插入测试用户 User user1(0, 张三, 22); // id为0插入时会自动自增 User user2(0, 李四, 25); db.insertUser(user1); db.insertUser(user2); // 3. 查询所有用户 db.queryAllUser(); // 4. 根据用户名查询单个用户 User queryUser db.queryUserByName(张三); if (queryUser.id ! 0) { std::cout 查询到用户id queryUser.id name queryUser.name age queryUser.age std::endl; } return 0; }