一、数据库基础概念
1.1 普通文件 VS 数据库
|-------------|------------------------|---------------------------|
| 对比项 | 普通文件 (txt/bin) | SQLite3 数据库 |
| 存储形式 | 文本 / 二进制文件 | 单 db 文件,包含表、索引、数据 |
| 增删改查 | 需要自己代码解析,效率低 | SQL 语句直接完成 CRUD,内置索引,查询高效 |
| 数据组织 | 自定义格式,无规范 | 二维表格,关系模型 |
| 并发访问 | 需要自己做读写保护 | 内置锁机制 |
| 部署 | 直接读写文件 | 链接 sqlite3 库,无后台服务进程 |
普通文件适合简单少量数据;当数据量大、频繁查询、条件筛选,优先选用数据库。
1.2 数据库分类
1. 关系型数据库:以二维表格存储数据
-
大型:Oracle、DB2
-
中型:MySQL、SQL Server
-
小型嵌入式:SQLite3
2. 非关系型数据库:键值、文档存储
-
Redis(内存键值数据库)
-
MongoDB(文档数据库)
1.3 SQLite3数据库特点
-
开源免费,纯C语言开发,代码量小,库体积10M以内,资源占用极低。
-
文件型数据库:全部数据保存在一个xxx.db文件,可以直接拷贝、迁移。
-
无服务进程:应用程序直接调用sqlite3库访问数据库,不需要启动后台数据库服务。
-
跨平台:Linux、Windows、Android都可以使用。
-
最大支持2TB数据库文件,满足嵌入式设备存储需求。
缺点:不适合高并发大量写入;不支持网络远程访问,只能本地访问。
二、SQLite3命令行工具使用
2.1 安装sqlite3
bash
Ubuntu/Debian
sudo apt-get install sqlite3
sudo apt-get install libsqlite3-dev C语言开发库,编译程序必须安装
2.2 进入数据库命令行
bash
sqlite3 stu.db
-
如果stu.db文件不存在,sqlite3会自动创建数据库文件;
-
如果文件已经存在,直接打开数据库。
注意:sqlite3命令行中,以.开头是点命令(工具内置),不带分号;SQL语句必须以分号;结尾。
常用点命令
sql
.help -- 查看帮助
.tables -- 查看数据库中所有表名
.headers on -- 打开查询结果表头显示
.mode column -- 格式化输出,列对齐
.quit -- 退出sqlite3命令行
可视化工具
-
命令行:sqlite3
-
图形工具:sqlitebrowser,可以打开db文件可视化查看表与数据
bash
sudo apt-get install sqlitebrowser
sqlitebrowser stu.db
三、SQLite3基础SQL语句
SQLite数据类型:
-
NULL:空
-
INTEGER:整型
-
REAL:浮点
-
TEXT:字符串文本
-
BLOB:二进制原始数据
3.1 创建数据表 CREATE TABLE
语法:
sql
CREATE TABLE 表名(列名1 类型,列名2 类型,列名3 类型...);
示例,创建学生表:
sql
CREATE TABLE class1(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
score REAL
);
-
PRIMARY KEY:主键,唯一标识一行记录;
-
AUTOINCREMENT:主键自动增长,插入数据不用手动填写id。
3.2 插入数据 INSERT
sql
--完整字段插入
INSERT INTO class1(name,score) VALUES("zhangsan",88.5);
--全部字段插入,主键自增写NULL
INSERT INTO class1 VALUES(NULL,"lisi",92.0);
TEXT字符串必须用双引号或者单引号包裹。
3.3 查询数据 SELECT
sql
--查询表全部列全部数据
SELECT FROM class1;
--只查询name、score两列
SELECT name,score FROM class1;
--条件查询,分数大于80
SELECT FROM class1 WHERE score80;
--多条件 and / or
SELECT FROM class1 WHERE score60 AND score<90;
--模糊匹配 %匹配任意多个字符,_匹配单个字符
SELECT FROM class1 WHERE name LIKE "zhang%";
--排序:ASC升序,DESC降序
SELECT FROM class1 ORDER BY score DESC;
3.4 修改数据 UPDATE
sql
UPDATE class1 SET score=95 WHERE id=1;
不加WHERE条件会修改表里面全部记录!开发务必小心。
3.5 删除数据 DELETE
sql
DELETE FROM class1 WHERE id=2;
不加WHERE条件会删除整张表全部数据。
3.6 删除表 DROP TABLE
sql
DROP TABLE class1;
四、SQLite3 C语言API编程
编译注意:使用sqlite3的C代码编译时,需要链接sqlite库:gcc main.c -o app -lsqlite3
4.1 核心API总览
|------------------|------------------------|
| 函数 | 功能 |
| sqlite3_open() | 打开 / 创建数据库,获取数据库句柄 |
| sqlite3_errmsg() | 获取错误信息字符串 |
| sqlite3_exec() | 执行 SQL 语句,支持回调函数处理查询结果 |
| sqlite3_close() | 关闭数据库,释放资源 |
1)sqlite3_open 打开数据库
include <sqlite3.h
int sqlite3_open(const char filename, sqlite3 ppDb);
-
filename:数据库文件路径,如"./stu.db";文件不存在自动创建;
-
ppDb:输出参数,数据库句柄指针,后续所有操作都使用这个句柄;
-
返回值:成功返回SQLITE_OK(0);失败返回非0错误码。
打开数据库不等于打开文件,sqlite内部会处理表、索引。
2)sqlite3_close 关闭数据库
int sqlite3_close(sqlite3 pDb);
用完数据库一定要close释放资源。
3)sqlite3_errmsg 获取错误信息
const char sqlite3_errmsg(sqlite3 pdb);
传入数据库句柄,返回错误描述字符串,方便打印调试。
4)sqlite3_exec(最重要)执行SQL语句
int sqlite3_exec(
sqlite3 pdb, //数据库句柄
const char sql, //要执行的SQL字符串
int (callback)(void,int,char,char), //查询回调函数
void arg, //传递给回调函数的自定义参数
char errmsg //输出错误信息
);
关键点:
-
增、删、改(INSERT / UPDATE / DELETE):没有返回结果集,callback填NULL;
-
SELECT查询语句:必须传入回调函数;查询到每一行记录,就会调用一次callback回调;
-
返回值:成功返回SQLITE_OK;失败非0。
查询回调函数原型
int callback(void arg, int n, char value, char name);
-
arg:sqlite3_exec传入的第四个参数;
-
n:当前这一行有多少列;
-
value\[\]:字符串数组,保存这一行每一列的数据;
-
name\[\]:字符串数组,保存每一列的表头字段名;
-
返回值:必须返回0,返回非0会终止查询。
4.2 完整C语言示例代码
include <stdio.h
include <sqlite3.h
include <string.h
/ 查询回调函数 /
int sql_callback(void arg, int col_cnt, char col_val, char col_name)
{
//打印一行数据
for(int i = 0; i < col_cnt; i++)
{
printf("%s = %s\t", col_namei, col_vali?col_vali:"NULL");
}
printf("\n");
return 0;
}
int main(void)
{
sqlite3 db;
char errmsg = NULL;
int ret;
//1.打开数据库,不存在则创建
ret = sqlite3_open("./stu.db", &db);
if(ret != SQLITE_OK)
{
printf("打开数据库失败:%s\n", sqlite3_errmsg(db));
return -1;
}
printf("数据库打开成功\n");
char sql_create = "CREATE TABLE IF NOT EXISTS class1("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT,"
"score REAL);";
ret = sqlite3_exec(db, sql_create, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("建表失败:%s\n", errmsg);
sqlite3_free(errmsg);
}
char sql_insert = "INSERT INTO class1(name,score) VALUES('zhangsan',88.5);";
ret = sqlite3_exec(db, sql_insert, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("插入失败:%s\n", errmsg);
sqlite3_free(errmsg);
}
//4.查询数据,传入回调函数接收结果
char sql_select = "SELECT FROM class1;";
printf("====查询结果====\n");
ret = sqlite3_exec(db, sql_select, sql_callback, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("查询失败:%s\n", errmsg);
sqlite3_free(errmsg);
}
sqlite3_close(db);
return 0;
}
编译命令:
bash
gcc sqlite_demo.c -o sqlite_demo -lsqlite3
./sqlite_demo
五、常见开发注意事项
-
SQL注入风险:不要直接用sprintf拼接外部输入内容到SQL语句;正式项目建议使用预处理接口sqlite3_prepare_v2。
-
errmsg内存:sqlite3_exec输出的errmsg,出错后需要调用sqlite3_free(errmsg)释放,避免内存泄漏。
-
回调函数:SELECT查询每一行调用一次回调;回调函数必须返回0,否则查询直接中断。
-
SQLite3写锁:SQLite数据库文件写的时候会加文件锁,多进程同时写会阻塞或者报错。
-
数据库文件权限:嵌入式开发注意db文件的读写权限,否则打开失败。
小结
-
SQLite3是嵌入式Linux首选轻量级关系数据库,单文件、无后台服务、C语言开发、资源占用低;适合设备本地存储。
-
掌握命令行工具sqlite3,熟悉点命令.tables .headers on .mode column .quit。
-
基础SQL:CREATE建表、INSERT插入、SELECT查询、UPDATE修改、DELETE删除、DROP删除表。
-
C语言核心API:sqlite3_open打开数据库,sqlite3_exec执行SQL,查询要注册callback回调,sqlite3_close关闭数据库。
-
编译程序必须链接-lsqlite3;开发注意内存释放、SQL注入、文件锁问题。