一、简介
SQLite 是一款轻型、遵守 ACID 的嵌入式关系型数据库引擎,由 D. Richard Hipp 于 2000 年发布并置于公有领域。
-
整个引擎仅一个 C 库,编译后< 1 MB,运行时< 64 kB RAM即可工作。
-
支持 Windows/Linux/Unix 及 Tcl、C#、PHP、Java、ODBC 等主流语言绑定。
-
在单连接、低并发、简单查询场景下性能优于 MySQL/PostgreSQL;高并发场景则相反。
-
截至 2025 年 6 月,最新稳定版为 3.49.1,项目已持续活跃 25 年。
**数据库的用途:**数据的存取。主要就是对表中的数据 增 、删 、查、改
1.1 SQLite3安装
核心:sudo apt-get install sqlite3 libsqlite3-dev(安装数据库)
如果安装失败,先尝试如下指令:
sudo apt-get update(更新软件源)
sudo apt-get install -f(更新软件依赖)验证安装成功的方法:
终端输入命令:sqlite3将进入到sqlite3命令行
1.2 数据库、表、记录(元组)、属性
数据库 :一系列数据类型的集合(图、表、二叉树、线性表.....),每个数据库存在数据库名, 通常以 xxxx.db 作为后缀
表 : 数据库下具体的一种数据类型,可以存在多张表(类比excl),每张表 存在 表名
关系 : 一种关系对应一张表
元组 :表中的一行或者一条记录
属性:表中的一列叫做一个属性,给每一个属性起一个具体的名称,就是属性名
二、常用操作
命令操作(注意前方的.)
.help:查看帮助信息,列出所有的系统命令
.exit:退出数据库
.quit:退出数据库
.databases:查看当前数据库信息
.tables:列出当前数据库中所有表的名字
.schema:列出数据库中所有表的结构
2.1 创建数据库
方式一 :sqlite3 xxx.db 若文件不存在就创建 并打开
xxx.db
,成为 main 数据库
方式二 :sqlite3.open xxx.db 先启sqlite3,若文件不存在就创建并打开
方式三 : sqlite3
.open xxx.db
.attach database 'xxx.db' as xxx; 连续创建多个数据库
在 SQLite 里,main 数据库就是你当前用
.open
打开(或命令行指定)的那个物理文件,所有不带模式前缀的表、索引、视图都默认创建在这个main数据库里.注意:当退出sqlite时再次启动并进入数据库后再次.databases,只会出现打开的那个库(
ATTACH
附加的数据库只在当前会话生效;一旦.quit
退出,所有附加库自动DETACH
,下次再进就只剩 main 了)
2.2 创建表
方式一 :create table 表名 (属性名 数据类型,属性名 数据类型,......);
方式二 :create table if not exists 表名 (属性名 数据类型,属性名 数据类型,......);例如:create table if not exists stu(id int,name char,sex char,score int);
创建表格的核心部分是create table 表名
if not exists 译为"如果不存在,则......"(可省略)
stu 是本例中表格的名字
(id int,name char,sex char,score int);是用于指定表格中各项属性,每个属性之间用逗号隔开。且每个属性采用格式: "属性名 数据类型" 属性数量自定义(注意末尾的分号)
会话里除了你自己的
stu.db
(main)之外,SQLite 还为你准备好了temp
这块"草稿纸",随时可用删除表:drop table if exists stu
|-----------|-------------------------|
| 存储类 | 含义 (SQLite 只有 5 个原生存储类) |
|integer
| 整数(1/2/3/4/6/8 字节自动变长) |
|real
| 8 字节 IEEE 浮点 |
|text
| UTF-8/UTF-16 字符串 |
|blob
| 二进制数据(原样保存) |
|null
| 空值 |
2.3 往表格中插入记录
方式一: insert into 表名 (所有属性名并逗号隔开) values (依次按数据类型全部赋值并逗号隔开);
方式二: insert into 表名 (部分属性名并逗号隔开) values (依次按数据类型部分赋值并逗号隔开);
方式三: insert into 表名 values (依次按数据类型全部赋值并逗号隔开);
**方式四:**insert into 表名 values (依次按数据类型全部赋值并逗号隔开),(依次按数据类型全部赋值并逗号隔开), (依次按数据类型全部赋值并逗号隔开);
例:
2.4 查询表中记录
方式一: select *from 表名;查找表中的所有数据
方式二:属性名 from 表名;查找表中的指定N个属性名的数据过滤并查询表中记录:
**方式一:**select * from 表名 where 属性名=属性值;
查询表中属性值对应的所有数据
方式二:select * from 表名 where 属性名=属性值 and 属性名=属性值;
查询表中属性值对应的所有数据--并列都满足的条件
方式三 :select * from 表名 where 属性名=属性值 or 属性名=属性值;
查询表中属性值对应的所有数据--任意满足一个的条件
*****可以理解为通配符,哪些列
select
要"选列",所以用***、
**where 限定"行"
2.5 删除表中记录
方式一 :delete from 表名 where 属性名=属性值;
删除属性名对应的属性值的记录
方式二 :delete from 表名;把表所有数据都删除
方式三 :delete from 表名 where 属性名=属性值 and 属性名=属性值 ;
方式四:delete from 表名 where 属性名=属性值 or 属性名=属性值 ;delete只"删行",无需列名,因此没有 **
*、
**where 限定"行"
2.6 更新记录属性
方式一: update 表名 set 要修改的属性名=要修改的属性值 where 依据属性名=属性值;
修改对应的属性中的属性值
方式二: update 表名 set 要修改的属性名=要修改的属性值;修改属性名中的所有属性值
2.7 添加属性(添加列)
方式一:alter table 表名 add column 属性名 属性类型;
2.8 删除属性(删除列)
SQLite3不允许直接删除一列,
可用三个步骤代替:
1.基于原表中部分属性,创造出一个新表(新表中的属性种类可以少于原表,相当于删除一些列)
2.删除原表
3.将新表重命名,修改为和原表相同
1.create table stu1 as select num,name,sex from stu;
基于表stu中的id、name和sex属性创建出一个新表stu1(复制记录)
2.drop table stu;从数据库文件中删除表stu
3.alter table stu1 rename to stu;
将表stu1重命名为stu
2.9 主键值
对于具有特定用途的表,表中通常存在一种或多种属性是每条记录不允许重复的。(比如:存储QQ账号的表,要求每条记录中QQ的ID号要互不相同;存储居民信息的表,要求每条记录中的身份号要互不相同......)
对于这类属性,可以在创建表的时候指定这种属性为主键值,则之后对于表格进行操作时,新增的任何记录中的主键值属性都不能相同,若相同,则操作失败。
主键值用法:
在创建表时指定属性为主键值。
create table stu(id int primary key, name text, password text);
三、相关API
3.1 sqlite3_open/sqlite3_open_v2 函数
函数原型: int sqlite3_open(const char *filename,sqlite3** ppDb)
函数功能: 打开一个数据库文件,如果文件不在则创建一个数据库并打开
函数参数:
@param1 :filename 数据库文件的名字(考虑路径), 数据库名字后缀 .db特殊值:
:memory:
- 创建内存数据库(临时,连接关闭后销毁)空字符串""- 创建临时磁盘数据库(连接关闭后自动删除)
NULL
- 创建临时内存数据库常规文件名-开或创建磁盘上的数据库文件
@param2 :ppdb 传出操纵数据库的二级指针,相当于句柄。
返回值: 成功:返回SQLITE_OK;失败:error_code 可以通过sqlite3_errmsg获取错误信息
注意:无论打开数据库成功与否,都需要关闭**函数原型:**int sqlite3_open_v2(const char*filename,sqlite3**ppDb,int flags,const char*zVfs)
函数功能: 以某种方式打开或者创建数据库函数参数:
@param1 :filename 数据库文件的名字(考虑路径), 数据库名字后缀 .db特殊值:
:memory:
- 创建内存数据库(临时,连接关闭后销毁)空字符串""- 创建临时磁盘数据库(连接关闭后自动删除)
NULL
- 创建临时内存数据库常规文件名-开或创建磁盘上的数据库文件
@param2:ppdb 传出操纵数据库的二级指针,相当于句柄。@param3:flags 打开标志
SQLITE_OPEN_READWREITE 读写方式打开
SQLITE_OPEN_CREATE 不存在则创建
SQLITE_OPEN_READONLY 只读的方式打开
SQLITE_OPEN_FULLMUTEX 启用线程安全
**@param4:**VFS名称(通常为NULL)**返回值:**成功:返回SQLITE_OK;失败:error_code 可以通过sqlite3_errmsg获取错误信息
3.2 sqlite3_close/sqlite3_close_v2函数
函数原型: int sqlite3_close(sqlite3* pDb)
函数功能: 关闭一个数据库
函数参数: pdb:操纵数据库的一级指针,句柄。
**返回值:**成功:返回SQLITE_OK, 失败:error_code 可以通过sqlite3_errmsg获取错误信息函数原型: int sqlite3_close_v2(sqlite3 *db);
**函数功能:**关闭数据库(推荐)
3.3 sqlite3_exec 函数
函数原型: int sqlite3_exec(sqlite3* pDB, const char *sql, sqlite_callback callback, void*para, char** errMsg);
函数功能: 对指定的数据库文件执行sql规定的指令。若这条指令能返回数据,则触发执行回调函数。
函数参数:
@param1: pDB 填sqlite3_open()的第二个参数,操作数据库的指针
@param2: sql 填待执行的数据库指令(注意:字符串形式 、尤其注意引号的使用--当执行指令中存在""时,需要把""使用 \" 转义)举例: "create table if not exists stu(id int primary key, name text, password text);"
@param3: callback 函数指针,指向一个回调函数.(如果是增删改操作,不需要用到回调函数,该参数可以填NULL; 如果是查询等操作,需要用到回调函数)
@param4: para 作为callback对应回调函数的实参@param5: errMsg 输出参数:返回错误信息
返回值:执行成功返回 SQLITE_OK,否则返回其他值回调函数: callback 回调函数的执行规则,sqlite3_exec()每查询到一条记录,基于这条记录执行一次回调函数
**函数原型:**typedef int (*sqlite_callback)(void* para,int columnCount,char** columnValue,char** columnName);
**函数功能:**由用户处理查询的结果
函数参数:
**@param1:**para 接收 sqlite3_exec()传入的第4个参数para;
**@param2:**columnCount, 查询到的这一条记录有多少个字段 (即这条记录有多少列);
**@param3:**columnValue,一个指针数组,查询出来的数据都保存在这里,它实际上是个 1 维数组(不要以为是 2 维数组),每一个元素都是一个 char * 值,是一条记录的内容(用字符串来表示,以'\0'结尾);
**@param4:**columnName,与 columnValue 是对应的,表示记录对应的属性名称。
举例:
cppint ret ; char* errMsg ; sqlite3 *qDB ; //用于指向待操作的数据库文件 //查询并显示表中数据(会用到回调函数 --> 帮助显示表中的记录) strcpy(action, "select * from QQ;"); ret = sqlite3_exec(qDB, action, print_record, NULL, &errMsg); if(ret != SQLITE_OK) { perror("select error!\n"); return -1; } /* 假设表中数据如下: 12345|zhangsan|111 23456|lisi |222 34567|wangwu |333 现在查询表中数据,执行指令select * from QQ; 那么回调函数会执行3次: 第1次执行,columnCount = 3,数组columnValue有3个元素"12345","zhangsan","111", 数组columnName有3个元素"id","name","password" 第2次执行,columnCount = 3,数组columnValue有3个元素"23456","lisi,"222", 数组columnName有3个元素"id","name","password" 第3次执行,columnCount = 3,数组columnValue有3个元素"34567","wangwu,"333", 数组columnName有3个元素"id","name","password" */ //将作为sqlite3_exec()的回调函数,执行查询表的指令时:每获取到一条记录,自动执行一次该函数 // sqlite3_exec的参数para;有多少列(属性/字段);char*数组,存所有属性的值;char*数组,存属性的名字 int print_record(void* para,int columnCount,char** columnValue,char** columnName) { static int cnt = 0; cnt++; printf("No.%d record! ", cnt); for(int i = 0 ;i < columnCount; i++) { printf("%s = %s ", columnName[i], columnValue[i]); } printf("\n"); //需要提供返回值! return 0; }
3.4 获取/释放表中数据
函数原型: int sqlite3_get_table(sqlite3* pDB, const char *sql,char ***pResult, int * rowCount,int * columnCount, char** errMsg);
函数功能: 执行 SQL 语句,通过一维数组返回结果;一般用于数据记录查询
函数参数:
输入参数:@param1 :pDB,打开的数据库句柄;
@param2: sql,待执行的 SQL 字符串,以' \0'结尾;输出参数 :
@param3: pResult,查询结果,是由字符串组成的一维数组(不要以为是二维数组,更不要以为是三维数组)。它的内存布局是:第一行是字段(属性)名称,后面紧接着每个字段的值;
@param4: rowCount,查询出多少条记录(即查出多少行);
@param5: columnCount,查询出来的记录有多少个字段(多少列);
@param6: errMsg,返回错误信息;
返回值:执行成功返回 SQLITE_OK,否则返回其他值函数原型:void sqlite3_free_table(char **result);
函数功能:释放查询结果占用的内存;
输入参数:result, 通过函数 sqlite3_get_table()查询到的记录结果;
输出参数:无
返回值:无
cppchar ** pResult; int row, column; sqlite3_get_table(qDB, "select * from QQ;", &pResult, &row, &column, &errMsg); printf("row = %d, column = %d\n", row, column); for(int i = 0; i< (row + 1) * column; i++)//之所以 row+1 还要算上 第一行的属性 { printf("%s, ", pResult[i]); } sqlite3_free_table(pResult); /**************【或】*******************/ printf("row = %d, column = %d\n", row, column); // 打印表头(第一行) for(int i = 0; i < column; i++) { printf("%-10s", pResult[i]); } printf("\n"); // 打印数据行 for(int i = 1; i <= row; i++) { for(int j = 0; j < column; j++) { printf("%-10s", pResult[i * column + j]); } printf("\n"); }
四、代码
gcc mysqlite3.c -lsqlite3 -o mysqlite3
cpp
/*编写函数:
1.创建一个数据库,创建一个4属性表
2.插入3行记录
3.使用回调函数,输出指定 name="李四"的该行信息
4.修改 name="张三" 该行记录中 id 改为 2
5.使用获取表中数据函数,得到标志所有信息
6.删除表
7.关闭数据库*/
#include<stdio.h>
#include<stdlib.h>
#include<sqlite3.h>
#include<string.h>
int print_record(void* para,int columnCount,char** columnValue,char** columnName)
{
static int cnt = 0;
cnt++;
printf("No.%d record! ", cnt);
for(int i = 0 ;i < columnCount; i++)
{
printf("%s = %s ", columnName[i], columnValue[i]);
}
printf("\n");
return 0;
}
int main()
{
/*1.创建一个数据库*/
int ret;
sqlite3* handler_stu;
char* errMsg=NULL;
ret = sqlite3_open("./student.db",&handler_stu);
if(ret!=SQLITE_OK)
{
printf("sqlite3_open error:%s\n",sqlite3_errmsg(handler_stu));
sqlite3_close(handler_stu);
return -1;
}
/*2.创建一个四属性表格*/
char action[1024];
strcpy(action,"create table if not exists stu(id int,name char,sex char,score int);");
ret = sqlite3_exec(handler_stu,action, NULL, NULL, &errMsg);
if(ret!=SQLITE_OK)
{
printf("sqlite3_exec create table error:%s\n",errMsg);
sqlite3_free(errMsg);
sqlite3_close(handler_stu);
return -2;
}
memset(action,0,sizeof(action));
/*3.插入一些数据*/
strcpy(action,"insert into stu values(1114,\"张三\",\"M\",123),(1115,\"李四\",\"M\",150),(1116,\"王五\",\"W\",100);");
ret = sqlite3_exec(handler_stu,action, NULL, NULL, &errMsg);
if(ret!=SQLITE_OK)
{
printf("sqlite3_exec insert error:%s\n",errMsg);
sqlite3_free(errMsg);
sqlite3_close(handler_stu);
return -3;
}
memset(action,0,sizeof(action));
/*4.使用回调函数,输出指定 name="李四"的该行信息*/
printf("=== 查询李四的信息 ===\n");
strcpy(action,"select * from stu where name = \"李四\";");
ret = sqlite3_exec(handler_stu,action, print_record, NULL, &errMsg);
if(ret!=SQLITE_OK)
{
printf("sqlite3_exec select error:%s\n",errMsg);
sqlite3_free(errMsg);
sqlite3_close(handler_stu);
return -4;
}
memset(action,0,sizeof(action));
/*5.修改 name="张三" 该行记录中 id 改为 2*/
strcpy(action,"update stu set id = 2 where name=\"张三\";");
ret = sqlite3_exec(handler_stu,action,NULL, NULL, &errMsg);
if(ret!=SQLITE_OK)
{
printf("sqlite3_exec updata error:%s\n",errMsg);
sqlite3_free(errMsg);
sqlite3_close(handler_stu);
return -5;
}
memset(action,0,sizeof(action));
/*6.使用获取表中数据函数,得到标志所有信息*/
printf("\n=== 获取表中所有信息 ===\n");
char **pResult;//查询的结果
int row ;//总行数,不算上属性
int column ;//总列数
ret = sqlite3_get_table(handler_stu,"select*from stu;",&pResult,&row,&column,&errMsg);
if(ret!=SQLITE_OK)
{
printf("sqlite3_get_table error: %s\n", errMsg);
sqlite3_free(errMsg);
sqlite3_close(handler_stu);
return -6;
}
printf("row = %d, column = %d\n", row, column);
// 打印表头(第一行)
for(int i = 0; i < column; i++)
{
printf("%-10s", pResult[i]);
}
printf("\n");
// 打印数据行
for(int i = 1; i <= row; i++)
{
for(int j = 0; j < column; j++)
{
printf("%-10s", pResult[i * column + j]);
}
printf("\n");
}
sqlite3_free_table(pResult);//释放表中数据
/*删除表*/
memset(action,0,sizeof(action));
strcpy(action,"drop table if exists stu;");
ret = sqlite3_exec(handler_stu,action,NULL, NULL, &errMsg);
if(ret!=SQLITE_OK)
{
printf("sqlite3_exec drop error:%s\n",errMsg);
sqlite3_free(errMsg);
sqlite3_close(handler_stu);
return -7;
}
sqlite3_close(handler_stu);
printf("数据库操作完成!\n");
return 0;
}