SQLite3数据库——Linux应用

一、简介

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 是对应的,表示记录对应的属性名称。

举例:

cpp 复制代码
int 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()查询到的记录结果;

输出参数:无

返回值:无

cpp 复制代码
char ** 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;
}
相关推荐
我科绝伦(Huanhuan Zhou)4 小时前
Systemctl 与 Systemd 全面指南:Linux 系统服务管理详解
linux·服务器·网络
倔强的石头1064 小时前
【Linux指南】Linux命令行进度条实现原理解析
android·linux
---学无止境---4 小时前
Linux中setup_arch和setup_memory相关函数的实现
linux
gplitems1234 小时前
Petslist – Pet listing WordPress Theme Free Download
linux·服务器·前端
1白天的黑夜14 小时前
Linux (5)| 入门进阶:Linux 权限管理的基础规则与实践
linux·运维·服务器·centos
济南java开发,求内推4 小时前
mongodb一个服务器部署多个节点
服务器·数据库·mongodb
武子康4 小时前
Java-148 深入浅出 MongoDB 聚合操作:$match、$group、$project、$sort 全面解析 Pipeline 实例详解与性能优化
java·数据库·sql·mongodb·性能优化·系统架构·nosql
程序猿(雷霆之王)5 小时前
MySQL——复合查询
数据库·mysql
xuecz12305 小时前
mmc-utils使用
linux·mmc