10_网络编程-数据库
本文最后更新于 2025-06-25,学习久了要注意休息哟
第七章 数据库
7.1 数据库的概念
7.1.1 数据
能够输入计算机并能被计算机程序识别和处理的信息结合
7.1.2 数据库 (database)
数据库是在数据库管理系统管理可控制下,存放在存储介质上的数据集合
7.1.3 数据库管理系统(DBMS)
DBMS 是数据库系统中 对数据管理进行同意管理可控制的软件系统
(1)数据库定义功能
(2)数据库操作功能
(3)数据库运行控制功能
(4)数据库通讯功能
(5)支持海量数据
7.1.4 文件管理特点
优点:
数据可以长期保存
能存储大量的数据
缺点:
数据的冗余大
数据一致性 完整性 难以维持
数据与程序缺乏高度独立性
7.1.5 数据库介绍
大型数据库
Oracle公司是最早开发关系型数据库的厂商之一,其产品支持最广泛的操作系统平台。目前Oracle关系型数据库产品的市场占有率名列前茅。
IBM的DB2是第一个具备网上功能的多媒体关系型数据库管理系统,支持包括 Linux 在内的一系列平台。
中型数据库
- Server是微软开发的数据库产品,主要支持Windows平台。
小型数据库
- MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL公司,2008年被Sun公司收购。开源代码。
7.1.6 基于嵌入式linux的数据库
基于嵌入式Linux的数据库主要有SQLite, Firebird, Berkeley DB, eXtremeDB
Firebird是关系型数据库,功能强大,支持存储过程、SQL兼容等
SQLite关系型数据库,体积小,支持ACID事务
Berkeley DB中并没有数据库服务器的概念,它的程序库直接链接到应用程序中
eXtremeDB是内存数据库,运行效率高
SQLite基础
SQLite的源代码是C,其源代码完全开放。SQLite第一个Alpha版本诞生于2000年5月。他是一个轻量级的嵌入式数据库。
SQLite有以下特性:
- 零配置——无需安装和管理配置;
- 存储在单一磁盘文件中的一个完整的数据库;
- 数据库文件可以在不同字节顺序的机器间自由共享;
- 支持数据库大小至2TB;
- 足够小,全部源代码大致3万行C代码,251KB;
- 比目前流行的大多数数据库对数据的操作要快。
7.1.7 安装 SQLite3
官网
https://www.sqlite.org/index.html
离线安装:
sudo dpkg -i sqlite3_3.22.0-1ubuntu0.4_amd64.deb # 数据库软件
sudo dpkg -i libsqlite3-dev_3.22.0-1ubuntu0.4_amd64.deb # 数据库的库文件
在线安装:
sudo apt-get install sqlite3 # 数据库
sudo apt-get install libsqlite3-dev # C语言操作数据库的API
验证安装
$ sqlite3
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>
退出需要按三次 ctrl + c
7.2 数据库语句和 SQL 语句
7.2.1 数据库语句
在命令前面 有 .
并不需要在命名后面加分号
1 打开数据库文件
方式1:
使用以下命令打开数据库文件,其中 文件名
可以是自定义名称,但通常以 .db
结尾。
sqlite3 文件名.db
示例:
$ sqlite3 HQYJ.db
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
sqlite> CREATE TABLE Log_in(id INT , User CHAR(64) , Password CHAR(64))
- 解释:
sqlite3 HQYJ.db
:打开名为HQYJ.db
的数据库文件。create table HQYJ aaa(id int);
:创建名为HQYJ
的表,包含id
字段。
方式2:
直接使用 sqlite3
命令进入 SQLite,然后通过 .open
命令打开数据库文件。
sqlite3
进入后执行:
sqlite> .open HQYJ.db
sqlite> .table
HQYJ
- 解释:
sqlite3
:启动 SQLite 并进入交互模式。.open HQYJ.db
:打开名为HQYJ.db
的数据库文件。.table
:显示数据库中所有的表。
2 SQLite3 数据库的系统命令
在 SQLite 中,系统命令以 .
开头,结尾不能加分号。这些命令可以通过 .help
来查看。
常见系统命令如下:
- .help:显示帮助菜单,查看所有可用命令。
- .open:打开数据库文件,格式为
.open 文件名
。 - .exit 或 .quit:退出 SQLite。
- .tables:查看当前数据库中的所有表。
- .schema:查看表的结构(建表语句)。
- .headers on/off:控制查询结果中是否显示表头信息。
3 数据库表结构说明
关系型数据库中的表通常由以下几个部分组成:
- 字段名:表示每个字段的名称(如
id
、name
等)。 - 数据类型:每个字段的数据类型(如
INTEGER
、TEXT
、CHAR
等)。 - 表中的数据:表中记录的实际内容,每条记录占据表中的一行。
- 表名:表的名称,用于标识数据库中的特定表。
7.2.2 SQL 语句
SQL 语句具有以下特点:
- 通用性: 大部分关系型数据库管理系统(如 MySQL、SQLite、PostgreSQL、SQL Server 等)的 SQL 语法基本相同,通用性很强。
- 语法规范: SQL 语句不能以
.
开头,且每条语句必须以分号(;
)结尾。 - 大小写不敏感: 在 SQL 语句中,关键字(如
SELECT
、FROM
等)对大小写不敏感,通常我们习惯将它们写成大写,以便提高可读性。
以下是常用的 SQL 语句示例,涵盖创建表、插入数据、查询、排序、更新和删除记录等操作,所有语句均符合 SQL 的通用特点。
1. 创建表
CREATE TABLE
语句用于创建表,并定义表的字段和数据类型。主键(PRIMARY KEY
)用于唯一标识每一条记录。
语法:
CREATE TABLE 表名 (
字段名1 数据类型1,
字段名2 数据类型2,
...
);
整型 INT
字符串 CHAR OR TEXT
示例:
CREATE TABLE log_in (
id INT PRIMARY KEY, -- 定义 id 为主键,自动唯一
User CHAR(50), -- 字符类型,固定长度为 50 个字符
password CHAR(50) -- 字符类型,固定长度为 50 个字符
);
2. 插入数据
INSERT INTO
语句用于向表中插入数据。可以插入所有字段的值,或仅插入指定字段的值。
语法:
INSERT INTO 表名 VALUES (值1, 值2, ...);
-- 或
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);
示例 1:插入所有字段
INSERT INTO log_in VALUES (1001, '张三', '密码123');
示例 2:插入指定字段
INSERT INTO log_in (id, password) VALUES (1003, '密码456');
注意:
- 字符串值需要用单引号
'
或双引号"
包裹。 - 未插入的字段将使用默认值或为空。
3. 查询数据
SELECT
语句用于从表中查询数据。可以查询所有字段,也可以查询指定字段。
语法:
SELECT 字段名1, 字段名2, ... FROM 表名;
-- 或
SELECT * FROM 表名;
示例 1:查询所有字段
SELECT * FROM log_in;
示例 2:查询指定字段
SELECT id, User FROM log_in;
4. 带条件的查询
使用 WHERE
子句可以根据条件过滤查询结果。
语法:
SELECT * FROM 表名 WHERE 条件;
示例 1:查询 id
为 1001 的记录
SELECT * FROM log_in WHERE id = 1001;
示例 2:查询 id
为 1001 且用户名为 '张三' 的记录
SELECT * FROM log_in WHERE id = 1001 AND User = '张三';
5. 排序查询结果
ORDER BY
子句用于对查询结果进行排序,默认是升序(ASC
),可以使用 DESC
指定降序。
语法:
SELECT * FROM 表名 ORDER BY 字段名 [ASC|DESC];
示例:按 id
降序排列
SELECT * FROM log_in ORDER BY id DESC;
6. 更新数据
UPDATE
语句用于修改表中的记录,WHERE
子句用于指定需要修改的记录。
语法:
UPDATE 表名 SET 字段名 = 新值 WHERE 条件;
示例:修改 id
为 1001 的记录的 password
UPDATE log_in SET password = '新密码' WHERE id = 1001;
7. 删除数据
DELETE
语句用于删除表中的记录,WHERE
子句用于指定要删除的记录。
语法:
DELETE FROM 表名 WHERE 条件;
示例:删除 id
为 1001 的记录
DELETE FROM log_in WHERE id = 1001;
8. 删除表
DROP TABLE
语句用于删除整个表及其所有数据。
语法:
DROP TABLE 表名;
示例:删除 log_in
表
DROP TABLE log_in;
9. 给表添加列
ALTER TABLE
语句用于向现有表中添加新列。
语法:
ALTER TABLE 表名 ADD COLUMN 列名 数据类型;
示例:向 log_in
表添加 email
列
ALTER TABLE log_in ADD COLUMN email CHAR(100);
10. 删除表中的列
在 SQLite 中,直接删除列的操作是不被支持的,也就是说,SQLite 不像一些其他数据库系统(如 MySQL、PostgreSQL)允许使用 DROP COLUMN
来删除列。为了解决这个问题,我们需要采取一个替代方法,即通过创建一个新的表来间接删除列。
由于 SQLite 不支持 DROP COLUMN
语法,我们可以按照以下步骤删除表中的列:
- 创建新表:新表的结构与旧表相同,但省略掉需要删除的列。
- 将旧表中的数据复制到新表:只复制保留的列数据。
- 删除旧表。
- 将新表重命名为旧表的名称。
删除表中的列的步骤
假设有一个名为 log_in
的表,其中我们需要删除 email
列:
CREATE TABLE log_in (
id INTEGER PRIMARY KEY,
User CHAR(50),
password CHAR(50),
email CHAR(100)
);
步骤 1:创建不包含 email
列的新表
CREATE TABLE new_log_in (
id INTEGER PRIMARY KEY,
User CHAR(50),
password CHAR(50)
);
步骤 2:从旧表复制数据到新表
INSERT INTO new_log_in (id, User, password)
SELECT id, User, password FROM log_in;
步骤 3:删除旧表
DROP TABLE log_in;
步骤 4:将新表重命名为旧表的名称
ALTER TABLE new_log_in RENAME TO log_in;
10. 主键定义
主键(PRIMARY KEY
)用于唯一标识每条记录。创建表时可以定义主键。
语法:
CREATE TABLE 表名 (
字段名 数据类型 PRIMARY KEY,
...
);
示例:为 log_in
表定义 id
为主键
CREATE TABLE log_in (
id INTEGER PRIMARY KEY, -- 定义 id 为主键
User CHAR(50),
password CHAR(50)
);
7.3 sqlite3 数据库API
使用sqlite3 提供的函数 ,编写代码时需要加头文件 #include
编译时 需要连接 sqlite3 的库 -lsqlite3
如果我们需要查看数据库说明不能使用man 了 需要去官网中的查看
这里我们介绍一些常用的API
7.3.1 相关api
打开数据库文件
文件 #include <sqlite3.h>
/* 打开数据库文件的函数 */
int sqlite3_open(const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
功能:打开一个数据库文件
参数:
filename: 数据库文件的名字
ppDb: 操作数据库的指针,句柄
返回值:
成功: SQLITE_OK
失败: 错误码
获取错误信息
/* 获取错误信息的函数 */
const char *sqlite3_errmsg(sqlite3 *db);
功能:获取错误信息描述
参数:返回的错误码 句柄
返回值:
错误码对于的信息
关闭文件
/* 关闭数据库的函数 */
int sqlite3_close(sqlite3 *db);
/* 功能:关闭一个数据库 */
执行sql语句
/* 执行 SQL 语句的函数 */
int sqlite3_exec(sqlite3 *db,
const char *sql,
int (*callback)(void*,int,char**,char**),
void *arg,
char **errmsg);
/* 功能:执行一条 SQL 语句 */
参数:
db : 数据库的句柄指针
sql : 将要执行的 SQL 语句
callback : 回调函数指针,只有在查询语句时,才会给回调函数传参
arg : 传递给回调函数的参数 , 只有在查询语句时,才会给回调函数传参
errmsg : 错误信息的地址
如果使用了errmsg 参数 需要使用sqlite3_free 函数进行释放
返回值:
成功:SQLITE_OK
出错:错误码 errcode
回调函数的使用
int callback(void *data, int argc, char **argv, char **azColName)
typedef int (*sqlite3_callback)(
void*, /* 在 sqlite3_exec() 的第 4 个参数中提供的数据 */
int, /* 行中的列数 */
char**, /* 表示行中字段的字符串数组 */
char** /* 表示列名的字符串数组 */
);
// 示例程序
int callback(void *data, int argc, char **argv, char **azColName)
{
for (int i = 0; i < argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
释放
sqlite3_free(void * )
7.3.2 api 的相关操作
1. 初始化操作
sqlite3 *sqlite3_init_log_in(void)
{
// 打开数据库
int sqlite_Errnum = 0;
sqlite3 *sqlite3_log_in;
char *errmsg;
sqlite_Errnum = sqlite3_open("log_in.db", &sqlite3_log_in);
if (SQLITE_OK != sqlite_Errnum)
{
printf("sqlite3_open : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, sqlite3_errmsg(sqlite3_log_in));
exit(-1);
}
printf("打开成功\n");
// 建立表
char sql_cmd[128];
sprintf(sql_cmd, "CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT , User CHAR(64), password CHAR(64))", Tab_name);
// INTEGER PRIMARY KEY AUTOINCREMENT 从 1 开始自增
// IF NOT EXISTS 当有表格时 不会报错
sqlite_Errnum = sqlite3_exec(sqlite3_log_in, sql_cmd, NULL, NULL, &errmsg);
if (SQLITE_OK != sqlite_Errnum)
{
printf("sqlite3_exec : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, errmsg);
sqlite3_close(sqlite3_log_in);
sqlite3_free(errmsg);
exit(-1);
}
// 释放报错信息
sqlite3_free(errmsg);
return sqlite3_log_in;
}
2. 插入操作
// 插入
void Insert_INTO_log_in(sqlite3 *sql)
{
// 用户名
char user[64];
// 密码
char password[64];
// 数据库错误码
int sql_err_num;
// 数据库错误信息
char * sql_err_str;
// 数据库命令
char sql_cmd[1024];
// 用户输入 插入的信息
printf("请输入用户名:");
scanf("%63s" , user);
printf("请输入用户密码:");
scanf("%63s" , password);
// 命令组装
snprintf( sql_cmd , sizeof(sql_cmd) , "INSERT INTO %s (User, password) VALUES ('%s' , '%s')" ,\
Tab_name , user , password );
// 执行命令
sql_err_num = sqlite3_exec( sql , sql_cmd , NULL , NULL , &sql_err_str );
if (SQLITE_OK != sql_err_num)
{
printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str );
sqlite3_free(sql_err_str);
return ;
}
printf("插入成功\n");
return ;
}
3. 删除操作
4. 查找操作
5. 修改操作
#include <head.h>
#define Tab_name "log_in"
// 初始化
sqlite3 *sqlite3_init_log_in(void);
// 插入
void Insert_INTO_log_in(sqlite3 *sql);
// 删除
void Delete_FROM_log_in(sqlite3 *sql);
// 查找
void Select_FROM_log_in(sqlite3 *sql);
// 修改
void Updata_SET_log_in(sqlite3 *sql);
// 回调函数
int callback(void *data, int argc, char **argv, char **azColName);
int main(int argc, char const *argv[])
{
// 创建表
sqlite3 *sql_log_in = sqlite3_init_log_in();
while (1)
{
printf("1、增加学生信息 2、删除学生信息 3、查找学生信息 4、修改学生信息 5、退出\n");
int sw_num;
scanf("%d", &sw_num);
switch (sw_num)
{
case 1: // 增加
Insert_INTO_log_in(sql_log_in);
break;
case 2: // 删除
Delete_FROM_log_in(sql_log_in);
break;
case 3: // 查找
Select_FROM_log_in(sql_log_in);
break;
case 4: // 修改
Updata_SET_log_in(sql_log_in);
break;
case 5:
sqlite3_close(sql_log_in);
return 0;
default:
printf("输入错误\n");
break;
}
}
sqlite3_close(sql_log_in);
return 0;
}
sqlite3 *sqlite3_init_log_in(void)
{
// 打开数据库
int sqlite_Errnum = 0;
sqlite3 *sqlite3_log_in;
char *errmsg;
sqlite_Errnum = sqlite3_open("log_in.db", &sqlite3_log_in);
if (SQLITE_OK != sqlite_Errnum)
{
printf("sqlite3_open : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, sqlite3_errmsg(sqlite3_log_in));
exit(-1);
}
printf("打开成功\n");
// 建立表
char sql_cmd[128];
sprintf(sql_cmd, "CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT , User CHAR(64), password CHAR(64))", Tab_name);
// INTEGER PRIMARY KEY AUTOINCREMENT 从 1 开始自增
// IF NOT EXISTS 当有表格时 不会报错
sqlite_Errnum = sqlite3_exec(sqlite3_log_in, sql_cmd, NULL, NULL, &errmsg);
if (SQLITE_OK != sqlite_Errnum)
{
printf("sqlite3_exec : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, errmsg);
sqlite3_close(sqlite3_log_in);
sqlite3_free(errmsg);
exit(-1);
}
// 释放报错信息
sqlite3_free(errmsg);
return sqlite3_log_in;
}
// 插入
void Insert_INTO_log_in(sqlite3 *sql)
{
// 用户名
char user[64];
// 密码
char password[64];
// 数据库错误码
int sql_err_num;
// 数据库错误信息
char *sql_err_str;
// 数据库命令
char sql_cmd[1024];
// 用户输入 插入的信息
printf("请输入用户名:");
scanf("%63s", user);
printf("请输入用户密码:");
scanf("%63s", password);
// 命令组装
snprintf(sql_cmd, sizeof(sql_cmd), "INSERT INTO %s (User, password) VALUES ('%s' , '%s')",
Tab_name, user, password);
// 执行命令
sql_err_num = sqlite3_exec(sql, sql_cmd, NULL, NULL, &sql_err_str);
if (SQLITE_OK != sql_err_num)
{
printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
sqlite3_free(sql_err_str);
return;
}
printf("插入成功\n");
return;
}
// 删除
void Delete_FROM_log_in(sqlite3 *sql)
{
// 用户id
int id;
// 数据库错误码
int sql_err_num;
// 数据库错误信息
char *sql_err_str;
// 数据库命令
char sql_cmd[1024];
// 输入用户id
printf("请输入要删除的ID:");
scanf("%d", &id);
// 组装命令 DELETE FROM log_in WHERE id = 1001;
snprintf(sql_cmd, sizeof(sql_cmd), "DELETE FROM %s WHERE id = %d",
Tab_name, id);
// 执行命令
sql_err_num = sqlite3_exec(sql, sql_cmd, NULL, NULL, &sql_err_str);
if (SQLITE_OK != sql_err_num)
{
printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
sqlite3_free(sql_err_str);
return;
}
printf("删除成功\n");
return;
}
// 查找
void Select_FROM_log_in(sqlite3 *sql)
{
// 用户id
int id;
// 数据库错误码
int sql_err_num;
// 数据库错误信息
char *sql_err_str;
// 数据库命令
char sql_cmd[1024];
// 是否有数据
int is = 0;
// 输入用户id
printf("请输入要删除的ID:");
scanf("%d", &id);
// 组装命令 SELECT * FROM 表名 WHERE 条件;
snprintf(sql_cmd, sizeof(sql_cmd), "SELECT * FROM %s WHERE id = %d",
Tab_name , id);
// 执行命令
sql_err_num = sqlite3_exec(sql, sql_cmd, callback , (void *)&is , &sql_err_str);
if (SQLITE_OK != sql_err_num)
{
printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
sqlite3_free(sql_err_str);
return;
}
if (is == 1)
{
printf("找到了\n");
return;
}
printf("没找到\n");
}
// 修改
void Updata_SET_log_in(sqlite3 *sql)
{
// 用户名
char user[64];
// 密码
char password[64];
// 用户id
int id;
// 数据库错误码
int sql_err_num;
// 数据库错误信息
char *sql_err_str;
// 数据库命令
char sql_cmd[1024];
// 是否有数据
int is = 0;
// 输入用户id
printf("请输入要删除的ID:");
scanf("%d", &id);
// 用户输入 修改的信息
printf("请输入用户名:");
scanf("%63s", user);
printf("请输入用户密码:");
scanf("%63s", password);
// 组装命令 UPDATE 表名 SET 字段名 = 新值 WHERE 条件;
snprintf(sql_cmd, sizeof(sql_cmd), "UPDATE %s SET User = '%s' , password = '%s' WHERE id = %d",
Tab_name, user , password , id);
// 执行命令
sql_err_num = sqlite3_exec(sql, sql_cmd, callback, (void *)&is, &sql_err_str);
if (SQLITE_OK != sql_err_num)
{
printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
sqlite3_free(sql_err_str);
return;
}
}
// 回调函数
int callback(void *data, int argc, char **argv, char **azColName)
{
for (int i = 0; i < argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
*((int *)data) = 1;
}
printf("\n");
return 0;
}
- 感谢你赐予我前进的力量