嵌入式 SQLite 数据库开发入门笔记
在嵌入式开发中,数据存储与管理是不可或缺的环节。对于资源有限的系统,轻量级数据库 SQLite 是一个非常理想的选择。它无需独立服务进程,直接嵌入到应用中即可使用,既能满足数据持久化需求,又不会过多占用系统资源。本文将结合实践代码,系统梳理 SQLite 在嵌入式中的使用方法。
一、SQLite 简介
-
定义
SQLite 是一个轻量级的关系型数据库管理系统(RDBMS),以文件形式存储数据,零配置、跨平台、易移植。
-
适用场景
-
嵌入式设备(路由器、物联网设备、手持终端)
-
本地应用配置存储
-
移动端(Android、iOS 应用)
-
-
数据组织结构
数据库(Database) -> 表(Table) -> 行(Row) -> 列(Column)
二、SQLite 命令行工具常用操作
SQLite 提供了简单的命令行工具,非常适合调试和学习。
命令 | 功能说明 |
---|---|
.help |
显示帮助信息 |
.database |
显示当前打开的数据库文件 |
.tables |
列出数据库中所有表 |
.schema 表名 |
查看表结构 |
.header on |
打开表头显示 |
.quit / .q |
退出 SQLite 命令行工具 |
-
常用 SQL 语法
-- 插入数据
INSERT INTO user VALUES (1, 'zhangsan', 25);-- 查询数据
SELECT * FROM user;
SELECT name, age FROM user WHERE age > 20;-- 更新数据
UPDATE user SET age=26 WHERE id=1;-- 删除数据
DELETE FROM user WHERE id=2;
三、C 语言调用 SQLite
在嵌入式开发中,我们通常通过 SQLite 提供的 C API 来操作数据库。
1. 基本流程
sqlite3 *db = NULL;
int ret = sqlite3_open("./aaa.db", &db);
if (ret != SQLITE_OK) {
fprintf(stderr, "sqlite3_open error: %s\n", sqlite3_errstr(ret));
sqlite3_close(db);
return 1;
}
char sql_cmd[] = "INSERT INTO user VALUES(11,'lisi',20);";
char *errmsg = NULL;
ret = sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
fprintf(stderr, "sqlite3_exec error: %s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return 1;
}
sqlite3_close(db);
-
sqlite3_open()
:打开数据库文件,不存在则新建。 -
sqlite3_exec()
:执行 SQL 语句。 -
sqlite3_close()
:关闭数据库。
四、回调函数处理查询结果
执行 SELECT
查询时,sqlite3_exec()
可以传入一个 回调函数,用来逐行处理结果。
1. 回调函数原型
int callback(void *arg, int col, char **result, char **title);
-
arg :用户自定义数据指针(
sqlite3_exec
的第四个参数传入)。 -
col:当前行的列数。
-
result:字符串数组,存放每列的值。
-
title:字符串数组,存放每列的列名。
👉 特性:
-
如果有多条结果,回调函数会被多次调用。
-
如果结果为空,回调函数不会被调用。
2. 示例代码
#include <sqlite3.h>
#include <stdio.h>
int show(void* arg, int col, char** result, char** title)
{
static int flag = 0; // 表头只打印一次
int i = 0;
if (flag == 0) {
flag = 1;
for (i = 0; i < col; i++) {
printf("%s\t", title[i]);
}
printf("\n");
}
for (i = 0; i < col; i++) {
printf("%s\t", result[i] ? result[i] : "NULL");
}
printf("\n");
return 0;
}
int main()
{
sqlite3* db = NULL;
char* errmsg = NULL;
int ret = sqlite3_open("./aaa.db", &db);
if (ret != SQLITE_OK) {
fprintf(stderr, "sqlite3_open %s\n", sqlite3_errstr(ret));
sqlite3_close(db);
return 1;
}
char sql_cmd[] = "SELECT * FROM user;";
ret = sqlite3_exec(db, sql_cmd, show, NULL, &errmsg);
if (ret != SQLITE_OK) {
fprintf(stderr, "sqlite3_exec error: %s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return 1;
}
sqlite3_close(db);
return 0;
}
3. 输出示例
假设表内容如下:
CREATE TABLE user (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);
INSERT INTO user VALUES (1, 'zhangsan', 25);
INSERT INTO user VALUES (2, 'lisi', 30);
程序运行结果:
id name age
1 zhangsan 25
2 lisi 30
五、嵌入式 SQLite 开发心得
-
数据库文件位置
- 嵌入式系统 Flash 容量有限,建议放在合适的分区,并避免频繁写入。
-
事务优化
-
默认每次写入都会同步到磁盘,效率低。
-
使用事务:
BEGIN TRANSACTION; INSERT INTO user VALUES(3,'wangwu',22); INSERT INTO user VALUES(4,'zhaoliu',28); COMMIT;
可以显著提高批量插入速度。
-
-
内存占用
- SQLite 默认内存消耗较低,但在嵌入式系统中仍需注意查询规模,避免一次性查询过大数据集。
-
回调 vs 预编译接口
-
sqlite3_exec()
简单易用,适合小型查询。 -
更复杂场景可使用 预编译语句 API (
sqlite3_prepare_v2
/sqlite3_step
/sqlite3_finalize
),性能更好。
-
六、总结
SQLite 在嵌入式系统中有以下优势:
-
单文件存储,移植方便
-
零配置、无需后台进程
-
支持标准 SQL,功能完备
-
资源占用低,适合嵌入式场景
通过本文的学习,你可以在嵌入式系统中完成数据库文件的创建、数据的增删改查,以及通过 回调函数 高效获取查询结果。