浙江大学实验报告
1. 实验目的和要求
- 设计并实现一个精简的图书管理系统,要求具有图书入库、查询、借书、还书、借书证管理等功能。
- 通过该图书馆系统的设计与实现,提高学生的系统编程能力,加深对数据库系统原理及应用的理解。
2. 实验内容和原理
- 自行设计数据库系统结构以完成相关需求。
- 使用C语言编码和mysql.h头文件函数。
3. 主要仪器设备
安装有MySQL和Visual Studio的电脑。
4. 操作方法和实验步骤
4.1 总体设计
4.1.1 系统架构
- 在数据库中规定过的管理员们可以对book,borrow,card三个表进行增删改查操作。
- 其余用户(无论是否有借书证)都可以查询图书馆里的书目藏书情况。其中可以进行复合多条件查询,并且自定义排序方式。
4.1.2 表结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0c7lzbBt-1651337582552)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419141307.png)]
根据需求创建表结构:
CREATE TABLE book (
bno INT PRIMARY KEY,
category CHAR ( 10 ),
title VARCHAR ( 40 ),
press VARCHAR ( 40 ),
YEAR INT,
author VARCHAR ( 20 ),
price DECIMAL ( 7, 2 ),
total INT CHECK ( total > 0 ),
stock INT CHECK ( stock >= 0 )
);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a64LluOx-1651337582552)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419141652.png)]
CREATE TABLE borrow (
cno CHAR ( 7 ) PRIMARY KEY,
bno INT, borrow_date date,
return_date date,
sa INT );
CREATE TABLE card (
cno CHAR ( 7 ) PRIMARY KEY,
NAME VARCHAR ( 10 ),
department VARCHAR ( 40 ),
type CHAR ( 1 ) CHECK ( type = 'U' OR type = 'T' OR type = 'G' OR type = 'O' )
);
CREATE TABLE sa (
id INT,
pas VARCHAR ( 30 ),
NAME VARCHAR ( 30 ),
telephone VARCHAR ( 11 )
);
4.2 详细设计
4.2.1 使用开发平台
Visual Studio 2022以及MySQL.
配置环境过程:
-
下载并安装MySQL。
-
下载并安装Navicat Premium使SQL可视化更方便。
-
将VS和MySQL进行连接,步骤如下:
-
打开项目属性
-
C/C++—常规—附加包含目录—添加MySQL include路径
-
连接器—常规—附加库目录—添加lib路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wldvMbOl-1651337582554)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419144223.png)]
-
链接器—输入—附加依赖项—添加libmysql.lib
-
后续在代码中添加
#include "mysql.h"
即可使用MySQL库。
-
4.2.2 mysql.h中的库函数
mysql_init
获得或初始化一个MYSQL结构。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v0ygi2ty-1651337582555)(C:/Users/86186/AppData/Roaming/Typora/typora-user-images/image-20220419145951845.png)]
mysql_real_connect
连接一个MySQL服务器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N9jf8q9m-1651337582555)(C:/Users/86186/AppData/Roaming/Typora/typora-user-images/image-20220419150049100.png)]
mysql_query
执行指定为一个空结尾的字符串的SQL查询。
后续的每一个具体模块都是通过此函数在MySQL中执行语句,需要实现的就是创建MySQL语句字符串即可,需要注意字符串结尾不是;
而是\0
。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q3mea11O-1651337582555)(C:/Users/86186/AppData/Roaming/Typora/typora-user-images/image-20220419150203987.png)]
mysql_store_result
检索一个完整的结果集合给客户。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gDTPT56u-1651337582556)(C:/Users/86186/AppData/Roaming/Typora/typora-user-images/image-20220419150249685.png)]
mysql_query(&mysql, "set names gbk")
防止中文查询结果乱码。
mysql_query(&mysql, "SET CHARACTER SET GBK")
保证插入成功。
4.2.3 连接数据库
bool ConnectDatabase() 函数
设置好相关信息,直接连接数据库。
bool ConnectDatabase() {
mysql_init(&mysql);
const char host[] = "localhost";//在本地创建的数据库
const char table[] = "library";//数据库的名称
const char user[] = "root";//设置的登录用户名
const char psw[] = "111111";//设置的登录密码
const int port = 3306;//端口
//使用库函数mysql_real_connect进行数据库连接
if (!(mysql_real_connect(&mysql, host, user, psw, table, port, NULL, 0))) {
printf("连接失败!!\n");
return false;
}
else {
printf("成功连接~\n");
return true;
}
}
4.2.4 管理员登录
void login() 函数
如果成功登录管理员,则返回true;如果是普通用户,则返回false。
bool login() {
int choice;
choice = 0;
do {
printf("请选择登录模式:1 普通用户 2 管理员 -1 退出\n");
scanf("%d", &choice);
if (choice == 1) {
return false;
}
else if (choice == 2) {
char pass[30];
printf("请输入编号:");
scanf("%s", &user);
printf("请输入密码:");
scanf("%s", &pass);
strcpy(query, "select * from sa where id = ");
strcat(query, user);
strcat(query, " and pas = '");
strcat(query, pass);
strcat(query, "'");
mysql_query(&mysql, "set names gbk");
mysql_query(&mysql, query);
char* str_field[32]; //定义一个字符串数组存储字段信息
res = mysql_store_result(&mysql);
for (int i = 0; i < 4; i++) //在已知字段数量的情况下获取字段名
{
str_field[i] = mysql_fetch_field(res)->name; //返回一个所有字段结构的数组。
}
//打印获取的数据
column = mysql_fetch_row(res); //在已知字段数量情况下,获取并打印下一行
if (column==nullptr) {
printf("请检查输入的账号密码或重新选择登录模式!!\n");
continue;
}
else {
printf("登陆成功~\n");
return true;
}
}
} while (choice != -1);
}
4.2.5 图书入库
void insertbook 函数
void insertbook() {
int num;
printf("请输入你要插入的书的个数:");
scanf("%d", &num);
char query[1000];
char values[100];
getchar();
int i;
for (i = 0; i < num; i++) {
gets_s(values);
mysql_query(&mysql, "SET CHARACTER SET GBK");
strcpy(query, "INSERT INTO book values");
strcat(query, values);
if (mysql_query(&mysql, query)) {
printf("插入成功!\n");
}
else {
printf("第%d条数据插入失败,请检查。\n", i + 1);
}
}
}
MySQL语句格式
INSERT INTO book values(....)
4.2.6 图书查询
findbook函数
(支持复合查询)
MySQL语句格式
SELECT * FROM book where (条件) order by (列) asc/desc #升序/降序
4.2.7 借书
borrowbook函数
void borrowbook() {
//输入借书证号返回所有已借的书
printf("请输入借书证号:");
char num[20];
scanf("%s", &num);
strcpy(query, "select * from card cno = '");
strcat(query, num);
strcat(query, "'");
mysql_query(&mysql, "set names gbk");
mysql_query(&mysql, query);
if (!(res = mysql_store_result(&mysql))) //获得sql语句结束后返回的结果集
{
printf("请输入正确的结束证号!\n");
}
strcpy(query, "select * from borrow where borrow_date is not null and return_date is null and cno = '");
strcat(query, num);
strcat(query, " ' ");
mysql_query(&mysql, "set names gbk");
mysql_query(&mysql, query);
if (!(res = mysql_store_result(&mysql))) //获得sql语句结束后返回的结果集
{
printf("该用户没有未还的书\n");
}
else {
char* str_field[32]; //定义一个字符串数组存储字段信息
for (int i = 0; i < 5; i++) //在已知字段数量的情况下获取字段名
{
str_field[i] = mysql_fetch_field(res)->name; //返回一个所有字段结构的数组。
}
for (int i = 0; i < 5; i++) //打印字段
printf("%15s", str_field[i]);
printf("\n");
//打印获取的数据
while (column = mysql_fetch_row(res)) //在已知字段数量情况下,获取并打印下一行
{
printf("%15s%15s%15s%15s%15s\n", column[0], column[1], column[2], column[3], column[4]); //column是列数组
}
}
printf("请输入要借的书的个数:");
int book_num;
scanf("%d", &book_num);
int j;
for (j = 0; j < book_num; j++) {
printf("请输入需要借的书的书号:");
char bno[12];
scanf("%s", &bno);
strcpy(query, "insert into borrow(cno,bno,borrow_date,sa) values (");
strcat(query, num);
strcat(query, ",");
strcat(query, bno);
strcat(query, ",now(),");
strcat(query, user);
mysql_query(&mysql, "SET CHARACTER SET GBK");
if (mysql_query(&mysql, query)) {
printf("借书成功\n");
}
else {
printf("借书失败,库存不足\n");
}
}
return;
}
MySQL语句格式
SELECT * FROM book where cno = in.cno
INSERT INTO borrow (cno,bno,borrow_date,sa) values(in.cno,in.bno,now(),sa)
#cno和bno需要手动输入 now()函数实现date类型的自动插入
#borrow后面的括号不写return_date使其默认为null
#sa是全局变量,为在login函数登陆时输入的id
余量为0不能再借 编写触发器
CREATE TRIGGER update_stock BEFORE INSERT ON borrow FOR EACH ROW
BEGIN
UPDATE book
SET stock = stock - 1
WHERE
bno = new.bno;
END
当余量为0时,本触发器要更新的余量会变成-1,违反了在建表时的约束(stock>=0),触发器执行失败,返回错误,因此借书的插入函数不能执行,实现余量为0不能借书的功能。
4.2.8 还书
returnbook函数
MySQL语句格式
UPDATE borrow SET return_date = now() where bno = in.bno and cno = in.cnp
还书后更新余量 编写触发器
CREATE TRIGGER add_stock AFTER UPDATE ON borrow FOR EACH ROW
BEGIN
UPDATE book
SET stock = stock + 1
WHERE
bno = old.bno and old.return_date is null and new.return_date is not null;
END
4.2.9 借书证管理
managecard函数
void managecard() {
printf("您要增加还是删除一个借书证?\n");
printf("1 增加 2 删除\n");
int choice;
scanf("%d", &choice);
if (choice == 1) {
char cno[12];
char name[30];
char department[30];
char type[2];
bool flag;
flag = false;
do {
printf("请输入新建的借书证号:");
scanf("%s", &cno);
strcpy(query, "select * from card where cno = '");
strcat(query, cno);
strcat(query, "'");
mysql_query(&mysql, "SET CHARACTER SET GBK");
mysql_query(&mysql, query);
if (!(res = mysql_store_result(&mysql))) //获得sql语句结束后返回的结果集
{
printf("借书证号已被占用!请重新输入!\n");
}
else flag = true;
} while (flag == false);
printf("请输入姓名:");
scanf("%s", &name);
printf("请输入学院:");
scanf("%s", &department);
printf("请输入卡的种类:");
scanf("%s", &type);
strcpy(query, "INSERT into card values ('");
strcat(query, cno);
strcat(query,"','");
strcat(query, name);
strcat(query,"','");
strcat(query, department);
strcat(query, "','");
strcat(query, type);
strcat(query, "')");
mysql_query(&mysql, "SET CHARACTER SET GBK");
if (mysql_query(&mysql, query)) {
printf("建卡成功!\n");
}
else {
printf("建卡失败\n");
}
}
else if (choice == 2) {
printf("请输入要删除的借书证号:");
char cno[10];
scanf("%s", &cno);
strcpy(query, "select * from borrow where return_date is null and cno = '");
strcat(query, cno);
strcat(query, "'");
mysql_query(&mysql, "SET CHARACTER SET GBK");
if (mysql_query(&mysql, query)) {
//删除
printf("删除成功\n");
}
else {
printf("该借书证还有未还的书!!删除失败\n");
}
}
}
MySQL语句格式
INSERT INTO card values(....)
DELETE FROM card where cno = in.cno
5.实验结果与分析
5.1 管理员登录
当账号密码不对时无法成功登录。
5.2 图书入库
只能在第二次插入的时候才成功插入(目前没找到原因qaq)
5.2.1 单本入库
(100,'摄影','影视镜头创作','中国友谊出版社',2019,'刘永思',128.00,1,1)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAT3MPAB-1651337582557)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419165654.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AwEZWSP3-1651337582557)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419165652.png)]
5.2.2 批量入库
(1,'摄影','绘画、摄影、电影','华中科技大学出版社',2021,'拉兹洛·莫霍利-纳吉',49.80,1,1)
(2,'摄影','新视觉 : 从材料到建筑','重庆大学出版社',2020,'拉兹洛·莫霍利-纳吉',38.00,2,2)
(3,'摄影','森山大道','北京美术摄影出版社',2017,'森山大道',98.00,2,2)
(4,'摄影','电视摄像','上海交通大学出版社',2018,'滕方',56.00,1,1)
(5,'摄影','拍出电影感','九州出版社',2021,'屠明非',180.00,1,1)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qx48txN4-1651337582557)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419165648.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kSnbtTxF-1651337582558)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419155810.png)]
5.3 图书查询
5.3.1 单一条件查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3Up88HQ-1651337582558)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419160219.png)]
5.3.2 复合查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AWByYR1n-1651337582558)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419160355.png)]
5.3 借书
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9AbSOLSQ-1651337582559)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419171622.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPN6MdCr-1651337582559)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419171658.png)]
5.4 还书
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qYxIapWV-1651337582559)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419171934.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y419iYnC-1651337582560)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419171958.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qE7gvYTd-1651337582560)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419172027.png)]
5.5 借书证管理
5.5.1 创建
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x7YgRJso-1651337582560)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419174053.png)]
5.5.2 删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XA5Fcm7W-1651337582561)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419174157.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1IFzU5X-1651337582561)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419174216.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CR3K8Tf6-1651337582562)(https://raw.githubusercontent.com/hinsew/photo/master/img/20220419174235.png)]
6. 讨论心得
- 善于利用已存在的库。
- 已使用函数连接则不需要再视图里进行设置。
- mysql_query执行成功返回0.
- 查找queryNULL值也算作有返回。
- 文件读写乱码修改txt编码模式。
附录
- 下载并安装MySQL和Navicat Premium参考[(26条消息) 新人向]MySQL和Navicat下载、安装及使用详细教程_向王同学敬礼的博客-CSDN博客_navicat下载安装以及配置
- 设置和连接VS和MySQL参考(26条消息) VS2017连接MYSQL 8.0(小白必看!)_v寰宇的博客-CSDN博客_vs连接mysql数据库
- mysql.h库函数参考(26条消息) C++ 连接数据库代码_Mr.禾的博客-CSDN博客_c++链接数据库
- mysql_query插入语句不成功解决办法参考mysql_query()插入不了数据解决方案 - 云+社区 - 腾讯云 (tencent.com)
ium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-2-82824693.142v9pc_search_result_cache,157v4control&utm_term=vs连接mysql数据库&spm=1018.2226.3001.4187) - mysql.h库函数参考(26条消息) C++ 连接数据库代码_Mr.禾的博客-CSDN博客_c++链接数据库
- mysql_query插入语句不成功解决办法参考mysql_query()插入不了数据解决方案 - 云+社区 - 腾讯云 (tencent.com)