目录
一、实验目的
二、实验内容
三、实验要求
四、实验设计
4.1需求分析
4.1.1系统目标
4.1.2功能需求
4.1.3性能需求
4.14界面需求
4.2概念模型设计
4.2.1 实体及联系
4.2.2 E-R图
4.3 逻辑设计
4.3.1 E-R模型向关系模型的转换
4.3.2 数据库逻辑结构
4.3.3数据库模型函数依赖集
4.4 物理设计
4.4.1创建表
4.4.2创建索引
4.5 数据库功能设计
4.5.1 数据初始化
4.5.2 图书借阅与归还
4.5.3 图书的预订与续借
4.5.4 学生信息调整
五、实验拓展
5.1 拓展原因
5.2 拓展思路
5.3 拓展功能设计
5.3.1 进入系统
5.3.2用户注册
5.3.3 用户登陆
5.3.4 学生端功能
5.3.5 管理员端功能
六、实验思考与讨论
6.1实验思考
6.1.1 对属性设置为NOT NULL的思考
6.1.3关于对学生功能如何实现的思考
6.1.4关于MYSQL与PYTHON进行交互实现图书管理系统数据库设计的思考
6.2实验讨论
6.2.1关于图形界面设计的讨论
6.2.2关于本次设计中所有信息表中主外键设计的讨论
七、实验总结与体会
一、实验目的
通过完成从用户需求分析、数据库设计到上机编程、调试和应用等全过程,进一步理解和掌握本书中的相关内容
二、实验内容
一个简单的图书管理系统包括图书馆内书籍的信息、学校在校学生的信息以及学生的借阅信息。此系统的功能分为面向学生和面向管理员两部分,其中,面向学生部分可以进行预订、借阅、续借、归还、查询书籍等操作;面向管理员部分可以完成书籍和学生的增加、删除和修改以及对学生预订、借阅、续借、归还的确认。
三、实验要求
3.2用SQL语句实现数据库的设计,并在MySQL上调试通过。
四、实验设计
4.1需求分析
4.1.1系统目标
本系统的目标是建立一个高效、易用、安全可靠的图书管理信息系统。
首先,我们将着重于数据库的建立和维护,确保数据一致性和完整性强,并采取措施确保数据的安全性。
其次,我们将开发一个功能完备、易于使用的MYSQL数据库系统,通过与python进行交互实现学生和管理员的登录、注册、个人信息管理、图书预订、借阅、归还、信息查询等功能。
在系统化、规范化和自动化方面,我们将努力提高信息处理的效率和准确性,为用户提供友好的界面和操作方式,以便轻松完成各种操作。最后,我们将采取各种措施保障系统的高效性、易用性和安全可靠性,以保护用户信息安全并保证系统运行稳定可靠。通过以上目标的实现,本系统旨在为图书管理信息化提供一种高效、便利、安全可靠的解决方案,为学生和管理员的图书管理工作提供有效支持和帮助。
4.1.2功能需求
·注册、登录:用户可以通过注册、登录使用图书管理系统,学生和管理员有不同的权限。
·图书预订:学生可以查看图书馆中的书籍并预订,同时可以取消预订。
·图书借阅:学生可以借阅图书,管理员可以批准借阅请求。
·图书归还:学生可以将借阅的图书归还给图书馆,管理员可以确认归还。
·图书续借:学生可以对已借阅的图书进行续借操作,管理员可以批准续借请求。
·学生信息调整:管理员可以管理学生信息,包括添加、删除、修改学生信息。
·图书信息调整:管理员可以管理图书信息,包括添加、删除、修改图书信息。
·学生操作确认:管理员需要对学生的借阅、预订和续借请求进行确认。
·信息查询:管理员和学生都可以查询图书馆的书籍、借阅记录和个人信息。
4.1.3性能需求
·响应时间:系统需要能够在短时间内响应用户的请求,避免用户等待过长时间。
·安全性:系统需要保证用户信息的安全性,如加密存储密码、权限控制等。
·可靠性:系统需要保证其可靠性,能够正常运行并处理异常情况。
4.14界面需求
·界面友好:系统需要提供友好的用户界面,易于使用和操作。
·界面美观:系统需要提供美观的用户界面,吸引用户使用和感受良好。
·响应迅速:系统需要提供快速响应的用户界面,避免用户等待过长时间。
4.2概念模型设计
4.2.1 实体及联系
根据需求分析我们规划出实体有:管理员信息实体、图书信息实体、学生信息实体。
联系有图书借阅、图书续借、图书预订、图书归还。
关系模型如下所示:
(1)图书(book_zzh)(编号,书名,作者,出版社,出版年份,语言,状态,在库数)
(2)学生(student_zzh)(学号,姓名,院系)
(3)管理员(administrator_zzh)(管理员编号,姓名)
(4)预订图书(reservedbook_zzh)(预订的书籍编号,预订的学生学号,预订时间)
(5)续借图书(renewedbook_zzh)(续借的书籍编号,续借的学生学号,续借时间)
(6)借阅图书(borrowedbook_zzh)(借阅的书籍编号,借阅的学生学号,借阅时间)
(7)归还图书(returnedbook_zzh)(归还的书籍编号,归还的学生学号,归还时间)
4.2.2 E-R图
(1)局部E-R图
①学生实体
·主键为学号
图4-1 学生实体E-R图
②管理员实体
主键为管理员编号
图4-2 管理员实体E-R图
③图书实体
主键为书号
图4-3 图书实体E-R图
④图书借阅联系
图4-4 图书借阅联系E-R图
⑤图书续借联系
图4-5 图书续借联系E-R图
⑥图书预订联系
图4-6 图书预订联系E-R图
⑦图书归还联系
图4-7 图书归还联系E-R图
(2)全局E-R图
图4-8 全局E-R图
4.3 逻辑设计
4.3.1 E-R模型向关系模型的转换
(1)实体类型的转换
将每个实体类型转换成一个关系模式,实体的属性即为关系的属性,实体标识符即为关系的键。
如下所示,将学生实体、图书实体、管理员实体转换为学生表、图书表、管理员表。
①图书表(book_zzh): book_id(主键), book_name, author, publisher, publish_year, language, status, total_num
②学生表(student_zzh): student_id(主键), student_name, department
③管理员表(administrator_zzh): admin_id(主键), admin_name
(2)联系类型的转换
①1:1联系类型转换:
可以在两个实体类型转换成的关系模式中的任意一个关系模式的属性中加入另一个关系模式的键和联系类型的属性。
本次数据库设计未出现此类型转换。
②1:n联系类型转换:
在n端实体类型转换成的关系模式中加入1端实体类型转换成的关系模式的键和联系类型的属性。
本次数据库设计未出现此类型转换。
③m:n联系类型转换:
将联系类型也转换成关系模式,其属性为两端实体类型的键加上联系类型的属性,而键为两端实体键的组合。
如预订及续借联系,为学生和图书实体间的m:n关系,因为这两种功能相对较为简单,可认为是图书与学生之间的二元关系。
I 预订图书表(reservedbook_zzh): book_id(外键,参考图书表中的book_id), student_id(外键,参考学生表中的student_id), reserve_time
II续借图书表(renewedbook_zzh): book_id(外键,参考图书表中的book_id), student_id(外键,参考学生表中的student_id), renew_time
④三元联系类型转换:
如果存在三元联系,可以将三元联系类型也转换成关系模式,其属性为关联的三个实体类型的键加上联系类型的属性,而键为三个实体键的组合。
在本次设计中,借阅关系和归还关系,都可以理解为学生实体、图书实体和管理员实体间的三元联系。
I 借阅图书表(borrowedbook_zzh): book_id(外键,参考图书表中的book_id), student_id(外键,参考学生表中的student_id), borrow_time
II 归还图书表(returnedbook_zzh): book_id(外键,参考图书表中的book_id), student_id(外键,参考学生表中的student_id), return_time
4.3.2 数据库逻辑结构
本部分将介绍在本次数据库系统设计中创建的表,并给出说明。
- 数据信息表
此表呈现了本次数据库设计中出现的数据库表的表名、其对应的关系模式名及中文说明。
表4-1数据信息表
数据库表名 | 对应的关系模式名 | 中文说明 |
book_zzh | 图书 | 图书信息表 |
student_zzh | 学生 | 学生信息表 |
administrator_zzh | 管理员 | 管理员信息表 |
reservedbook_zzh | 预订图书 | 图书预订信息表 |
renewedbook_zzh | 续借图书 | 图书续借信息表 |
borrowedbook_zzh | 借阅图书 | 图书借阅信息表 |
returnedbook_zzh | 归还图书 | 图书归还信息表 |
(2)图书信息表
表4-2 book_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
book_id | VARCHAR | 20 | PRIMARY KEY | NOT NULL | 书号 |
book_name | VARCHAR | 50 | NOT NULL | 书名 | |
author | VARCHAR | 50 | 作者 | ||
publisher | VARCHAR | 50 | 出版社 | ||
publish_year | YEAR | 4 | 出版年 | ||
language | VARCHAR | 20 | 语种 | ||
status | VARCHAR | 10 | 状态 | ||
total_num | INT | 在库数 |
(3)学生信息表
表4-3 student_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
student_id | INT | PRIMARY KEY | NOT NULL | 学号 | |
student_name | VARCHAR | 30 | NOT NULL | 姓名 | |
department | VARCHAR | 50 | 院系 |
(4)管理员信息表
表4-4 administrator_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
admin_id | INT | PRIMARY KEY | NOT NULL | 管理员编号 | |
admin_name | VARCHAR | 30 | NOT NULL | 姓名 |
(5)图书借阅信息表
表4-5 borrowedbook_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
book_id | VARCHAR | 20 | FOREIGN KEY | NOT NULL | 书号 |
student_id | INT | FOREIGN KEY | NOT NULL | 学号 | |
borrow_time | DATETIME | 50 | 借阅时间 |
(6)图书预订表
表4-6 reservedbook_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
book_id | VARCHAR | 20 | FOREIGN KEY | NOT NULL | 书号 |
student_id | INT | FOREIGN KEY | NOT NULL | 学号 | |
reserve_time | DATETIME | 50 | 预订时间 |
(7)图书续借表
表4-7 renewedbook_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
book_id | VARCHAR | 20 | FOREIGN KEY | NOT NULL | 书号 |
student_id | INT | FOREIGN KEY | NOT NULL | 学号 |
(8)图书归还表
表4-8 returnedbook_zzh
字段名 | 字段类型 | 长度 | 主键或外键 | 字段值约束 | 对应中文属性名 |
book_id | VARCHAR | 20 | FOREIGN KEY | NOT NULL | 书号 |
student_id | INT | FOREIGN KEY | NOT NULL | 学号 | |
return_time | DATETIME | 50 | 归还时间 |
4.3.3数据库模型函数依赖集
主要考虑函数依赖集和第三范式
(1)图书表(book_zzh)
①主键:book_id
②非主键属性:book_name, author, publisher, publish_year, language, status, total_num
③函数依赖集:
book_id -> book_name, author, publisher, publish_year, language, status, total_num
book_name, author, publisher, publish_year, language, status -> total_num
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(book_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
(2)学生表(student_zzh)
①主键:student_id
②非主键属性:student_name, department
③函数依赖集:student_id -> student_name, department
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(student_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
(3)管理员表(administrator_zzh)
①主键:admin_id
②非主键属性:admin_name
③函数依赖集:admin_id -> admin_name
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(admin_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
(4)预订图书表(reservedbook_zzh)
①主键:(book_id, student_id)
②非主键属性:reserve_time
③函数依赖集:(book_id, student_id) -> reserve_time
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(book_id, student_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
(5)续借图书表(renewedbook_zzh)
①主键:(book_id, student_id)
②非主键属性:renew_time
③函数依赖集:(book_id, student_id) -> renew_time
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(book_id, student_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
(6)借阅图书表(borrowedbook_zzh)
①主键:(book_id, student_id)
②非主键属性:borrow_time
③函数依赖集:(book_id, student_id) -> borrow_time
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(book_id, student_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
(7)归还图书表(returnedbook_zzh)
①主键:(book_id, student_id)
②非主键属性:return_time
③函数依赖集:(book_id, student_id) -> return_time
④第三范式(3NF):是
分析:该表符合第一范式(1NF)的要求,每个属性都是原子性的。它也符合第二范式(2NF)的要求,因为非主键属性完全依赖于候选键(book_id, student_id)。此外,该表也符合第三范式(3NF)的要求,不存在传递函数依赖关系。
通过上述分析,我们可了解到每个表的主键、非主键属性以及函数依赖关系。
同时,我们也可以得出结论,即每个表都符合第三范式(3NF)的要求,从而提高了数据库的数据一致性和减少了数据冗余。
4.4 物理设计
本部分主要介绍DDL,即数据定义语言,包括创建、修改和删除表、定义约束、创建索引等
4.4.1创建表
(1)图书表的创建
- - 创建图书表
- CREATE TABLE book_zzh (
- book_id VARCHAR(20) PRIMARY KEY,
- book_name VARCHAR(50) not null ,
- author VARCHAR(50),
- publisher VARCHAR(50),
- publish_year YEAR(4),
- language VARCHAR(20),
- status VARCHAR(10),
- total_num INT
- );
- desc book_zzh;
表结构查询结果
图4-9图书表结构查询结果
(2)学生表的创建
- -- 创建学生表
- CREATE TABLE student_zzh (
- student_id INT PRIMARY KEY,
- student_name VARCHAR(30) not null ,
- department VARCHAR(50)
- );
- desc student_zzh;
表结构查询结果
图4-10学生表结构查询结果
(3)管理员表的创建
- -- 创建管理员表
- CREATE TABLE administrator_zzh (
- admin_id INT PRIMARY KEY,
- admin_name VARCHAR(30) not null
- );
- desc administrator_zzh;
表结构查询结果
图4-11管理员表结构查询结果
(4)图书借阅信息表的创建
- -- 创建借阅图书表
- CREATE TABLE borrowedbook_zzh (
- book_id VARCHAR(20),
- student_id INT,
- borrow_time DATETIME,
- PRIMARY KEY (book_id, student_id),
- FOREIGN KEY (book_id) REFERENCES book_zzh (book_id),
- FOREIGN KEY (student_id) REFERENCES student_zzh (student_id)
- );
- desc borrowedbook_zzh;
图4-12 借阅图书表结构查询结果
(5)图书预订信息表的创建
- -- 创建预订图书表
- CREATE TABLE reservedbook_zzh (
- book_id VARCHAR(20),
- student_id INT,
- reserve_time DATETIME,
- PRIMARY KEY (book_id, student_id),
- FOREIGN KEY (book_id) REFERENCES book_zzh (book_id),
- FOREIGN KEY (student_id) REFERENCES student_zzh (student_id)
- );
- desc reservedbook_zzh;
表结构查询结构
图4-13 预订图书表结构查询结果
(6)图书续借信息表的创建
- -- 创建续借图书表
- CREATE TABLE renewedbook_zzh (
- book_id VARCHAR(20),
- student_id INT,
- renew_time DATETIME,
- PRIMARY KEY (book_id, student_id),
- FOREIGN KEY (book_id) REFERENCES book_zzh (book_id),
- FOREIGN KEY (student_id) REFERENCES student_zzh (student_id)
- );
- desc renewedbook_zzh;
表结构查询结构
图4-14 续借图书表结构查询结果
(7)图书归还信息表的创建
- -- 创建归还图书表
- CREATE TABLE returnedbook_zzh (
- book_id VARCHAR(20),
- student_id INT,
- return_time DATETIME,
- PRIMARY KEY (book_id, student_id),
- FOREIGN KEY (book_id) REFERENCES book_zzh (book_id),
- FOREIGN KEY (student_id) REFERENCES student_zzh (student_id)
- );
- desc returnedbook_zzh;
表结构查询结果
图4-15 归还图书表结构查询结果
4.4.2创建索引
索引是数据库中用于快速查找和访问数据的数据结构,可以提高查询效率和数据检索速度。需要注意的是,索引也会带来一些额外的开销。如会占用磁盘空间,同时导致性能略微下降。因此,只有在需要频繁进行查询的列上创建索引,以权衡索引的好处和开销。
主键(Primary Key)和外键(Foreign Key)列通常是需要创建索引的。
本数据库系统索引建立情况如下
- #基于键码建立索引
- -- 为book_zzh表的book_id字段建立索引
- CREATE INDEX idx_book_id ON book_zzh (book_id);
- -- 为student_zzh表的student_id字段建立索引
- CREATE INDEX idx_student_id ON student_zzh (student_id);
- -- 为administrator_zzh表的admin_id字段建立索引
- CREATE INDEX idx_admin_id ON administrator_zzh (admin_id);
- -- 为reservedbook_zzh表的book_id和student_id字段组合建立索引
- CREATE INDEX idx_reservedbook_ids ON reservedbook_zzh (book_id, student_id);
- -- 为renewedbook_zzh表的book_id和student_id字段组合建立索引
- CREATE INDEX idx_renewedbook_ids ON renewedbook_zzh (book_id, student_id);
- -- 为borrowedbook_zzh表的book_id和student_id字段组合建立索引
- CREATE INDEX idx_borrowedbook_ids ON borrowedbook_zzh (book_id, student_id);
- -- 为returnedbook_zzh表的book_id和student_id字段组合建立索引
- CREATE INDEX idx_returnedbook_ids ON returnedbook_zzh (book_id, student_id);
若需要对某个表的索引建立情况进行查询,则可以使用如下语句(以book_zzh表为例)
- SHOW INDEX FROM book_zzh;
查询结果与实际情况一致
图4-16 图书表索引查询结果
4.5 数据库功能设计
4.5.1 数据初始化
此部分包括三个事务的执行,即添加学生信息、添加图书信息和添加管理员信息
(1)学生信息的添加
- #添加学生信息
- INSERT INTO student_zzh (student_id, student_name, department)
- VALUES
- (10011, '张三', '计算机学院-计算机科学与技术'),
- (10012, '李四', '软件学院-软件工程'),
- (10013, '王五', '信息学院-信息安全'),
- (10014, '赵六', '计算机学院-计算机应用'),
- (10015, '钱七', '数字媒体艺术学院-数字媒体技术'),
- (10016, '孙八', '网络与信息安全学院-网络工程'),
- (10017, '周九', '物联网工程学院-物联网工程'),
- (10018, '吴十', '电子商务学院-电子商务'),
- (10019, '郑十一', '软件学院-软件工程'),
- (10020, '郭十二', '计算机学院-计算机科学与技术');
如代码所示,我们添加了十名学生的信息,包括学号、姓名和院系。接下来我们对其进行查询,使用查询语句SELECT * FROM student_zzh;查询结果如下:
图4-17 学生信息查询结果
(2)图书信息的添加
①说明:在表结构设计过程中,重点考虑了“状态”和“在库数”两个属性的设置。首先“状态”用于显示每本图书的当前状态,默认三种取值:可借、已预订、已借。但是考虑到实际情况,图书数据库中一种书不可能只存在一本,因此我另外设计了“在库数”属性,显示该种书的在库数。书号对应该本书的状态,书名对应该种书的在库数。
②代码:我向数据库中添加了大约20本书。包括中文和英文书籍,且部分书籍的在库数为2,所有书籍的初始状态均为“可借”。
- INSERT INTO book_zzh (book_id, book_name, author, publisher, publish_year, language, status, total_num)
- VALUES
- (1, '《围城》', '钱钟书', '南昌大学出版社', 2010, '中文', '可借', 2),
- (2, '《围城》', '钱钟书', '南昌大学出版社', 2010, '中文', '可借', 2),
- (5, '《1984》', '乔治·奥威尔', '南昌大学出版社', 2008, '中文', '可借', 2),
- (6, '《1984》', '乔治·奥威尔', '南昌大学出版社', 2008, '中文', '可借', 2),
- (9, '《红楼梦》', '曹雪芹', '南昌大学出版社', 2003, '中文', '可借', 2),
- (10, '《红楼梦》', '曹雪芹', '南昌大学出版社', 2003, '中文', '可借', 2),
- (13, '《人类简史》', '尤瓦尔·赫拉利', '南昌大学出版社', 2009, '中文', '可借', 2),
- (14, '《人类简史》', '尤瓦尔·赫拉利', '南昌大学出版社', 2009, '中文', '可借', 2),
- (21, '《To Kill a Mockingbird》', '哈珀·李', '南昌大学出版社', 2007, '英文', '可借', 1),
- (24, '《The Great Gatsby》', 'F·斯科特·菲茨杰拉德', '南昌大学出版社', 2014, '英文', '可借', 1),
- (25, '《The Catcher in the Rye》', 'J·D·塞林格', '南昌大学出版社', 2005, '英文', '可借', 1),
- (26, '《Harry Potter and the Philosopher\'s Stone》', 'J·K·罗琳', '南昌大学出版社', 2003, '英文', '可借', 1),
- (28, '《The Lord of the Rings》', 'J·R·R·托尔金', '南昌大学出版社', 2007, '英文', '可借', 1),
- (29, '《The Chronicles of Narnia》', 'C·S·刘易斯', '南昌大学出版社', 2008, '英文', '可借', 1),
- (30, '《The Da Vinci Code》', '丹·布朗', '南昌大学出版社', 2009, '英文', '可借', 1);
对插入结果进行查询,如下所示
图4-18 图书信息查询结果
(3)管理员信息的添加
①说明:考虑实际情况,管理员数目我们仅初始化两位,后续也可以进行注册。属性正常设置“管理员编号”和“姓名”。
②代码
- -- 插入两个管理员信息
- INSERT INTO administrator_zzh (admin_id, admin_name)
- VALUES
- (10086, '橘右京'),
- (12306, '凯');
查询插入结果,如下所示
图4-19 管理员信息查询结果
4.5.2 图书借阅与归还
此项包括三个核心事务,即学生借阅图书和归还图书,还有利用SQL语句对图书借阅和归还信息的查询。
注:
本次实验采用的是Python与MySQL进行交互来设计和管理图书管理系统的数据库。Python提供了多个库和模块,如mysql-connector-python、pymysql等,可以方便地连接和操作MySQL数据库。通过交互实现图书借阅、续借、预订及归还的功能将在下一模块展示。本部分主要展示利用mysql执行图书借阅等事务。
(1)学生借阅图书
①说明:首先思考应该如何实现图书借阅,一个很容易的思路是向图书借阅信息表中插入一条记录,然后对图书表中的某些属性如状态和在库数进行适当的修改。为了提高数据库性能,简化复杂逻辑,保证数据安全,降低维护成本。我们将借阅图书这一功能封装为一个存储过程,参数为借阅的书号和学生学号。通过调用该存储过程即可实现图书借阅功能。
一个值得讨论的点是借阅的条件,首先当然是“可借”状态的数据可以被借阅。然后是“已预订”状态,如果本人预订的书籍本人是否可以预订呢?我们在代码中作出了如下处理:即出现此情况时,同样认定为不可借阅,并且提示用户“该书已预订,请去图书馆领取预订的书籍”。这样处理就不会和之前的情况冲突。
②代码
- # 图书借阅功能
- DELIMITER //
- CREATE PROCEDURE borrow_book(IN IN_book_id VARCHAR(20), IN IN_student_id INT)
- BEGIN
- DECLARE book_status VARCHAR(10);
- DECLARE total_count INT;
- DECLARE v_book_name VARCHAR(50);
- -- 检查学生是否已经预订了这本书
- SELECT COUNT(*) INTO @reserved_count FROM reservedbook_zzh WHERE book_id = IN_book_id AND student_id = IN_student_id;
- IF @reserved_count > 0 THEN
- -- 将已预订的书设定为不可借阅,即使是预订图书的本人。
- SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '您已经预订了这本书,请先去图书馆领取预订的图书。';
- ELSE
- -- 获取图书状态和已借出数量
- SELECT status, total_num, book_name INTO book_status, total_count, v_book_name FROM book_zzh WHERE book_id = IN_book_id LIMIT 1;
- IF book_status = '可借' AND total_count > 0 THEN
- -- 更新图书状态为已借
- UPDATE book_zzh SET status = '已借' WHERE book_id = IN_book_id;
- -- 获取书号对应的书名
- SELECT book_name INTO v_book_name FROM book_zzh WHERE book_id = IN_book_id;
- -- 更新图书状态为已借出,更新图书在库数,减一;由书名得到在库数
- UPDATE book_zzh SET total_num=total_num-1 WHERE book_name=v_book_name;
- -- 插入借阅信息
- INSERT INTO borrowedbook_zzh (book_id, student_id, borrow_time) VALUES (IN_book_id, IN_student_id, NOW());
- SELECT '图书借阅成功。';
- ELSE
- SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该图书不可借阅或已全部借出,请选择其他图书。';
- END IF;
- END IF;
- END //
- DELIMITER ;
③功能展示
首先我们利用语句“call borrow_book('1','10011');”调用存储过程。为了能够同时观察到借阅信息表和图书信息表是否同步实现了信息的更新,我们建立一个视图student_borrow_info,其能够同时显示学生学号、姓名、书名、书号、借阅时间及归还时间(此处采用左外连接,如果没有归还,则归还时间为空)。
代码如下(对列名采用了别名,提高易读性)
图4-20 视图创建代码截图
查询视图结果如下
图4-21 视图查询结果
通过以上内容,我们可以分析出该系统很好的实现了图书的借阅功能,即同步实现了图书表状态和在库数的更新,同时将借阅信息插入了图书借阅信息表中。
(2)学生归还图书
①说明:如何实现图书归还功能,参考图书借阅,一个很简单的思路是首先将归还信息插入到图书女归还信息表中,然后对图书信息表中的属性“状态”、“在库数”进行更新。我将此功能同样封装成了一个存储过程,参数是书号和学生学号。通过调用该存储过程实现图书归还功能。
②代码
- #图书归还功能
- DELIMITER //
- CREATE PROCEDURE return_book (IN IN_book_id VARCHAR(20), IN IN_student_id INT)
- BEGIN
- -- 定义局部变量
- DECLARE record_count INT;
- DECLARE v_book_name VARCHAR(50);
- -- 查询借阅记录是否存在
- SELECT COUNT(*) INTO record_count FROM borrowedbook_zzh WHERE book_id = IN_book_id AND student_id = IN_student_id;
- IF record_count > 0 THEN
- -- 更新书号对应的图书状态为可借
- UPDATE book_zzh SET status = '可借' WHERE book_id = IN_book_id;
- -- 获取书号对应的书名
- SELECT book_name INTO v_book_name FROM book_zzh WHERE book_id = IN_book_id;
- -- 将该类书的在库数加1
- UPDATE book_zzh SET total_num = total_num + 1 WHERE book_name = v_book_name;
- -- 插入归还信息
- INSERT INTO returnedbook_zzh (book_id, student_id, return_time) VALUES (IN_book_id, IN_student_id, NOW());
- -- 该语句不会在python中输出
- SELECT '图书归还成功。';
- ELSE
- SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该图书未被借阅或借阅记录不存在。';
- END IF;
- END //
- DELIMITER ;
③功能展示
首先调用存储过程,对张三同学借阅的《围城》进行归还。
call return_book('1','10011');
查询视图student_borrow_info,结果如下
图4-22 视图查询结果
分析结果,对于张三同学的这条记录,借阅时间和归还时间都存在,且图书状态和在库数都合理。该系统很好的实现了图书归还功能。
4.5.3 图书的预订与续借
本部分主要实现学生端的另外两个功能:预订和续借。另外还有利用SQL语句对图书预订和续借信息的查询。
本次实验采用的是Python与MySQL进行交互来设计和管理图书管理系统的数据库,交互实现将在下一模块展示。本部分主要展示利用mysql执行图书预订和续借等事务。
(1)学生预订图书和取消预订图书
①说明:如何实现图书预订功能,我们首先需要利用书号对图书状态进行查询,当该书状态为“可借”时,可进行预订。预订后将书的状态更新为“已预订”,图书将预订信息插入图书预订信息表。
另外在预订图书功能的基础上,为了更加贴近实际需要,我增加了取消预订功能。由于学生对状态为“可借”的图书进行预订后,图书状态由“可借”变为“已预订”,首先根据学号和书号查询是否有预订记录,如果有则将预订信息表中的相应记录删除,同时更新图书状态为“可借”。
②代码
I 预订图书代码
- # 定义存储过程,实现图书预订功能
- DELIMITER //
- CREATE PROCEDURE reserve_book(IN IN_book_id VARCHAR(20), IN IN_student_id INT)
- BEGIN
- DECLARE book_status VARCHAR(10);
- -- 获取图书状态,由于知识面限制,目前仅支持单书查询
- SELECT status INTO book_status FROM book_zzh WHERE book_id = IN_book_id LIMIT 1;
- IF book_status = '可借' THEN
- -- 更新图书状态为已预订
- UPDATE book_zzh SET status = '已预订' WHERE book_id = IN_book_id;
- -- 插入预订信息
- INSERT INTO reservedbook_zzh (book_id, student_id, reserve_time) VALUES (IN_book_id, IN_student_id, NOW());
- SELECT '图书预订成功。';
- ELSE
- SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该图书不可预订,请选择其他图书。';
- END IF;
- END //
- DELIMITER ;
II 取消预约图书代码
- #取消预订
- DELIMITER //
- CREATE PROCEDURE cancel_reservation_sp (IN p_book_id INT, IN p_student_id INT)
- BEGIN
- DECLARE record_count INT;
- # 检查预订信息表中是否有数据
- SELECT COUNT(*) INTO record_count FROM reservedbook_zzh WHERE book_id = p_book_id AND student_id = p_student_id;
- IF record_count > 0 THEN
- # 取消预订,即删除预订信息表中的数据
- DELETE FROM reservedbook_zzh WHERE book_id = p_book_id AND student_id = p_student_id;
- #更新图书状态
- UPDATE book_zzh SET status = '可借' WHERE book_id = p_book_id;
- SELECT '取消预订成功' AS message;
- ELSE
- SELECT '该图书未被预订或预订记录不存在' AS message;
- END IF;
- END //
- DELIMITER ;
③功能展示
I 图书预约功能展示
首先调用存储过程预约一本图书call reserve_book('13','10019');
为了查看信息的方便,我设计了另一个视图student_borrow_info_plus ,将学生表、图书表、借阅信息表、预订信息表、归还信息表中的属性进行了合并,代码如下所示
图4-23 视图创建代码
使用了COALESCE函数来合并借阅信息和预订信息,确保即使只有预订信息而没有借阅信息的记录也能够被显示出来。
接下来查询视图,结果如下
图4-24 视图查询结果
分析结果可知系统很好的实现了图书预约功能。
II 取消图书预约功能展示
首先我们调用存储过程cancel_reservation_sp,语句如下:
call cancel_reservation_sp('13',10019);
然后查询视图,观察上一条记录是否存在
图4-25 视图查询结果产生变化
结果显示,预订记录已被删除,即系统实现了取消图书预订的功能。
(2)学生续借图书
①说明:首先是确定图书续借的对象,即当前状态为“已借”的书籍。然后将学号、书号及当前续借时间插入续借信息表中。续借成功后提示用户“图书续借成功。请一个月内及时归还!”。若图书为其他状态,则提示不可续借。
②代码
- #图书续借功能
- DELIMITER //
- CREATE PROCEDURE renew_book(IN IN_book_id VARCHAR(20), IN IN_student_id INT)
- BEGIN
- DECLARE book_status VARCHAR(10);
- -- 获取图书状态
- SELECT status INTO book_status FROM book_zzh WHERE book_id = IN_book_id LIMIT 1;
- IF book_status = '已借' THEN
- -- 更新续借记录中的续借次数和续借时间
- INSERT INTO borrowedbook_zzh (book_id, student_id, borrow_time) VALUES (IN_book_id, IN_student_id, NOW());
- SELECT '图书续借成功。请一个月内及时归还!';
- ELSE
- SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该图书不可续借,请选择其他图书。';
- END IF;
- END //
- DELIMITER ;
③功能展示
由于之前借阅的书已归还,因此我们首先借阅一本书。
call borrow_book('1','10012');
为了更好的显示出借阅时间、续借时间、归还时间之间的关系,我建立了视图
student_borrow_info_plus_2,代码如下
图4-26 视图创建代码
在上一个视图的基础上,删除了预订相关的列和表,并添加“最晚归还时间”一列,方便管理员对超时未归还的同学进行管理。
借阅后查询视图
图4-26 视图查询结果
此表很有意思的一点是,两次借阅的是同一本书,但图书状态都是已借出。这是因为第一条记录中的书籍在被借阅及归还后,状态被更新为“可借”,而后另一位同学又借阅了此书,状态又更新为了已借出。第二次进行了续借处理。
然后调用存储过程实现续借
call renew_book('1','10012');
查询视图结果,续借时间及最晚归还时间都已给出
图4-27 视图查询结果产生变化
分析查询结果可知该系统很好的实现了图书续借功能。
4.5.4 学生信息调整
此部分为主要面向管理员的操作。包括对学生信息的增删改。
最初是打算将增删改操作封装为一个存储过程统一进行操作,提高代码的复用性和可维护性。但是后面尝试后发现封装成一个存储过程反而会使操作更加繁琐且不可控。
因为它们的操作之间差异比较大,造成存储过程的优势并不明显。此外,存储过程还会增加一定的开发和维护成本。
因此,在仅使用mysql语句的情况下,我认为在对学生信息的增删改操作相似性较低的情况下,直接使用增删改语句可能更为简单和直接。
(1)增加学生信息
①说明:直接使用SQL 中的数据操纵语言(DML)-insert语句
格式如下(支持多组数据同时添加)
INSERT INTO 表名 (列1, 列2, 列3, ...)
VALUES (值1, 值2, 值3, ...);
②功能展示
mysql语句如下
insert into student_zzh(student_id, student_name, department) VALUES ('8008','嘉禾望岗','信息工程学院-人工智能');
然后对学生表进行查询
图4-28 学生信息增加
观察学生表可知,该学生信息已经成功添加进数据库。
(2)修改学生信息
①说明:同样直接使用SQL 中的数据操纵语言(DML)语句update
格式如下:
UPDATE 表名
SET 列1 = 值1, 列2 = 值2, ...
WHERE 条件;
②功能展示-将嘉禾望岗同学的学号修改为“10086”
Mysql语句如下:
update student_zzh set student_id=10086 where student_name='嘉禾望岗';
查询学生表确定是否完成修改
图4-29 学生信息修改
(3)删除学生信息
①说明:使用SQL 中的数据操纵语言(DML)语句delete
格式如下
DELETE FROM 表名
WHERE 条件;
②功能展示-删除姓名为钱七的学生信息
delete from student_zzh where student_name='钱七';
查询学生表可知姓名为“钱七”的学生信息已被删除。
图4-30 学生信息删除
4.5.5 图书信息调整
同学生信息调整一样,此功能主要面向管理员进行操作。同样是考虑到封装成存储过程反而会使操作更加繁琐且不可控,因此使用使用SQL 中的数据操纵语言(DML)语句实现图书信息的增删改。
(1)增加图书信息功能展示
SQL语句:INSERT INTO book_zzh (book_id, book_name, author, publisher, publish_year, language, status, total_num)
VALUES
('20', '《活着》', '余华', '南昌大学出版社', 1998, '中文', '可借', 1);
即插入书号为20,书名为《活着》的书籍
查询图书表
图4-31 图书信息增加
结果显示该书的信息已经插入到图书表中。
(2)修改学生信息功能展示
SQL语句:UPDATE book_zzh
SET book_id = 99, publisher = '清华大学出版社'
WHERE book_id = 29;
查询图书表
图4-32 图书信息修改
观察结果可知,该书书号已被修改为‘99’,且出版社更新为“清华大学出版社”。
(3)删除学生信息功能展示
①SQL语句
- select book_name into @v_book_name from book_zzh where book_id='10';-- 红楼梦
- delete from book_zzh where book_id='10';
- update book_zzh set total_num=total_num-1 where book_name=@v_book_name;
②说明:删除操作较前两种操作复杂一点,因为当删除一本书后,该种书可能还存在,即需要更新该书号对应书名的在库数。
上面代码的逻辑是先通过待删除书的书号查询书名,然后对信息进行删除,最后更新书号对应记录的在库数。
③查询图书表
图4-33 图书信息删除
结果显示《红楼梦》从两本变为了一本,记录也被删除了一条。
五、实验拓展
5.1 拓展原因
在本次图书管理系统数据库设计过程中,我尝试面向学生和管理员端来完成本次系统的设计。但在设计的过程中,遇到了一些问题,如进行图书借阅查询时,站在用户的角度,首先应该是进行书籍信息的查询,此搜索过程可以通过输入书籍关键字实现。因此这些功能的实现需要进行数据的输入。而MYSQL若需实现数据输入功能,则需要通过 Python 与 MySQL 数据库进行交互。
另一个很重要的原因是,通过与python进行交互,可以更方便的对数据库进行管理同时也方便对功能的展示。常用的Python库是 mysql-connector-python,它提供了与 MySQL 数据库进行连接、执行 SQL 语句以及获取查询结果等功能。
5.2 拓展思路
首先通过终端输入“pip3 install mysql-connector-python”
安装mysql-connector-python库,它提供了简单直观的 API,使得 Python 开发人员能够方便地与 MySQL 数据库进行交互,从而实现数据库应用的设计和开发。
在与数据库实现连接后进行功能设计。第一步是对用户注册和登陆功能进行了完善。在原有表的基础上,我另外设计了用户信息表,属性分别是用户编号和用户密码,编号对应学号或管理员编号。只有用户完成注册、数据导入数据库后,才能成功登陆系统。
进入界面后,首先选择进入学生端或者管理员端。进入操作端后完成注册及登陆操作。学生端开放的功能有图书借阅、图书续借、图书预订、图书查询和图书归还功能。管理员端开放的功能有学生信息调整、图书信息调整及对图书/学生信息的查询,包括借阅信息、归还信息、预订信息及续借信息,以此实现对学生操作的确认。
为了功能的实际性,学生端及管理员端都提供了退出系统功能。
另外,为了设计的美观,我将功能选择以图形界面的形式呈现,具体是通过调用python中的Tkinter 库实现,它提供了创建窗口、按钮、文本框以及其他常见 GUI 元素的功能。具体功能设计将在下一部分实现。
5.3 拓展功能设计
5.3.1 进入系统
此部分设计了一个"400x400"大小的窗口,我将“枫.png”设置为其背景。并设置两个按钮,分别对应学生端入口和管理员入口。运行后的部分界面如下
图5-1 系统启动界面
5.3.2用户注册
(1)首先创建一个新用户,并赋予其全部权限,同时设置好密码。
图5-2 新用户创建(略)
(2)调用mysql-connector-python库将其与数据库进行连接
mydb.cursor() 方法用于创建一个游标对象,使得开发人员可以使用该对象执行 SQL 语句和操作数据库。
图5-3 数据库连接代码(略)
注:实验拓展部分的代码将全部以截图形式呈现
(3)用户信息的输入与导入数据库
①思路
I 首先显示用户注册按钮,点击后逐行输入信息
(以学生端为例)
图5-4 学生端注册
输入的信息有学号、姓名、院系及密码。为了数据的安全性,通过‘*’对密码输入进行了实时保护。
图5-5 学生信息输入代码
II数据导入数据库
首先检查学号是否存在,若存在则提示用户"该学号已经被注册,请重新输入"。
图5-6 学生信息导入数据库
②功能展示
注册/登陆界面
图5-7 学生端界面
点击新用户注册后
图5-8 学生端注册界面
分别查询学生表和用户表验证是否注册成功
图5-9学生表查询结果
图5-10 用户表查询结果
以上查询结果均显示注册成功。
5.3.3 用户登陆
(1)设计思路及实现(以学生用户为例)
用户在注册成功后将自动跳转到登陆界面。用户需要输入用户编号,学生用户需输入学号及密码。输入完成后点击登陆键即可。
图5-11 用户登陆代码
具体是通过输入的学号和密码查询用户信息表,若存在该记录则显示登陆成功,进入功能选择界面
(2)功能展示
进入登陆界面输入信息
图5-12 用户登陆界面
点击按钮输入成功后将自动跳转到功能选择界面
图5-13 用户功能选择
5.3.4 学生端功能
由于整体功能在物理设计部分已全部展示,且受篇幅限制,本部分仅展示图书借阅功能、图书预订功能及图书归还功能。
(1)图书借阅功能
①说明:相较于仅使用MYSQL实现的借阅功能,与python进行交互后,借阅功能有了更人性化的变化,即可实现数据输入功能。
首先是添加了图书搜索功能。
为了更贴近实际,我们采用关键词搜索,即用户可通过输入书名或作者查询需要借阅的书籍。然后将关联的书籍列出,每本书书号不同。用户可根据图书状态即在库数选择书籍进行借阅。
用户输入需要借阅书籍的书号,然后程序调用借阅书籍的存储过程。实现借阅功能。
核心代码如下图所示:
图5-14 借阅图书功能核心代码
②功能展示
I 首先用户点击功能选择界面的“图书借阅”按钮,然后控制台会提示用户输入关键字进行图书搜索。
如下所示,我输入关键词“余华”,由于该书仅一本,因此只有一条搜索记录。
图5-15 第一次借阅
查询视图student_borrow_info_plus
图5-16 视图查询结果
可以观察到《活着》该书已被借阅,且借阅时间已经导入数据库,此外状态被修改为已借,在库数被修改为0.
II 为了验证搜索方式的多样性,我们进行第二次借阅。
输入关键词“T”,检索结果如下
图5-17 第二次借阅
本次我们借阅的是《The Da Vinci Code》,其相关信息均已显示出。
图5-18 视图查询结果
视图查询结果均显示借阅成功。
(2)图书归还功能
①说明:考虑到还书时,书号是用户可以直接从书上查找到的。因此我们设置用户还书时只需要输入书号及学号。
代码如下
图5-19 图书归还核心代码I
归还函数return_book()如下所示
图5-20 图书归还核心代码II
②功能展示
假设我们需要还的书是《The Da Vinci Code》,因此我们输入其编号。流程如下所示:
图5-21 图书归还
查询视图结果
图5-22 图书归还结果
由结果可得到,该书的归还时间已经导入数据库,状态已经更新为“可借”,在库数也从0更新为1。很好的实现了图书归还功能。
(3)图书预订功能
①说明:与借阅图书相似,同样是首先进行通过输入关键词实现图书检索。然后用户可选择预订图书或取消预订。接下来用户只需输入需预订书籍的编号和本人学号即可完成操作。
核心代码如下
图5-23 图书预订核心代码
②功能展示
I 首先进行图书检索,我输入“钱钟书”,结果如下
图5-24 图书检索
II 尝试预订一本状态为“已借”的书籍
图5-25 预订图书的特殊情况处理
显然,由于该书已预订,不可预订。体现了系统对边缘情况的处理。
III 尝试预订编号为2的书籍
图5-26 预订图书
查询预订表结果
图5-27 预订图书结果
IV 尝试对该书进行借阅,结果如下
图5-28 借阅图书的特殊情况处理
由于借阅了已经预订的书,系统提示用户前往图书馆领取已预订的图书,很好的体现了系统设计的全面性。
V 接下来取消对该书的预订,如下所示
图5-29 取消图书预订
查询预订信息表
图5-30 取消图书预订结果
可见该预订记录已被删除。
5.3.5 管理员端功能
受篇幅限制,本部分仅展示学生信息查询功能。
我们尝试查询学生借阅图书信息(归还/续借/预订信息的查询操作类似)
(1)说明:在MYSQL中我编写了存储过程GetBorrowedBooks_zzh,代码如下
图5-31 核心存储过程代码
在调用时,系统提示用户输入需要查询的信息对应的日期。若输入all,则输入全部的学生借阅信息。
(2)功能展示
要求输出全部的借阅信息
图5-32 管理员查询借阅信息
在控制台输出的效果如下
图5-33 管理员查询结果
六、实验思考与讨论
在完成本次数据库设计的过程,遇到了很多问题,也产生了很多思考,包括一些细节和整体设计方向方面的想法。具体如下
6.1实验思考
6.1.1 对属性设置为NOT NULL的思考
属性设置为NOT NULL但default的结果仍然为NULL产生了疑惑
比如我设置了book_zzh表中的书号和书名设置为了非空
图6-1 book_zzh表部分内容
但表结构中default项的结果却是NULL
图6-2 book_zzh表结构部分内容
查阅资料后发现,
表中的<NULL>表示的是未设置默认值,同时了解到以上几条原则
①MySQL 中,如果你创建表时不指定默认值,并且该列允许 NULL 值,那么当你向表中插入数据时,该列将默认为 NULL。
②如果不允许 NULL 值,则在定义列时需要将其设置为 NOT NULL。
如果你定义了不允许 NULL 值的列,并且在插入新行时未为该列指定值,则会发生错误,MySQL将拒绝插入该行并返回错误消息。
③如果在创建表时指定了某列为 NOT NULL,但没有显式地为其指定默认值,那么该列的默认值将为 MySQL 的默认值。MySQL 中各数据类型的默认值如下:
INT, BIGINT, FLOAT, DOUBLE 等数值类型的默认值为 0。
VARCHAR, TEXT 等字符串类型的默认值为空字符串 ''。
DATE, DATETIME, TIMESTAMP 等时间类型的默认值为特定日期或时间。
6.1.2关于图书表属性中“状态”和“在库数”的设计
上文已有提及,“状态”的设计是为了迎合学生端中的借阅、归还和预订等操作。而“在库数”的设计是考虑到现实情况中每种书可能存在多本的情况。因此我认为设计在库数是很有必要的。
6.1.3关于对学生功能如何实现的思考
在刚开始做本次实验时,想到的只是编写一定量的mysql语句来实现功能。后面联想到了编程语言中的函数封装,于是才打算将每个功能设计成对应的存储过程。在需要时进行调用。
同时存储过程还有很多优点,如提高性能、简化安全性管理、提高代码复用性、支持事务处理、降低耦合性、提供数据一致性和完整性。
在与python进行交互后,也只需要简单的调用存储过程即可。
6.1.4关于MYSQL与PYTHON进行交互实现图书管理系统数据库设计的思考
上文已有提及,最初尝试交互实现的原因之一是单一使用MYSQL进行设计很难实现数据的控制台输入,而通过与python交互则能很好的解决此问题。有了数据输入功能,诸如图书借阅、归还、续借和预订的设计都能丰富很多。
另一方面,使用MySQL与Python进行交互实现图书管理系统的数据库设计具有高度的灵活性、易于管理和维护、数据处理效率高、开发效率高和可扩展性高等优势,我认为是一个很正确的尝试。
6.2实验讨论
6.2.1关于图形界面设计的讨论
最开始进行这一步是基于兴趣和美观性的考虑。再大二学习了web前端开发后,对这方面的设计十分有兴趣。于是在深入学习python中tkinter库后,进行了本次设计。
另一方面,将功能的选择转换成界面上的按钮选择,更贴近现实设计需求,也使界面更加美观。
6.2.2关于本次设计中所有信息表中主外键设计的讨论
本次图书管理系统的主外键设计具有以下特点和特性:
(1)主键的唯一性:每个表都有一个主键,用于唯一标识表中的每条记录。通过主键的唯一性,可以确保每本书、每个学生和每个管理员都有一个唯一的标识符,避免数据冗余和重复。
(2)外键的关联性:使用外键来建立表与表之间的关联关系,实现数据的一致性和完整性。通过外键,可以确保借阅、预订、续借和归还等操作只能在已存在的图书和学生记录之间进行,避免了无效的操作和错误的数据关联。
(3)复合主键的应用:部分表中使用了复合主键,由多个字段组成。这是因为涉及到多对多的关系,一个学生可以借阅、预订、续借和归还多本书,一本书也可以被多个学生进行这些操作。通过复合主键,可以唯一标识每条记录并保持数据的完整性。
(4)数据一致性的保证:通过主外键的设计,可以保证数据在不同表之间的一致性。例如,在借阅操作时,需要先检查学生和图书是否存在于对应的表中,以及图书是否可借阅,这样可以避免出现学生借阅不存在的图书或借阅已被预订的图书等情况。
(5)索引的优化:主键和外键字段通常会创建索引,以提高查询和关联操作的性能。通过合理地使用索引,可以加快系统的数据检索速度,提高系统的响应效率。
总体而言,这样的主外键设计可以确保数据的完整性、一致性和准确性,同时提供了有效的关联关系和查询性能。通过合理的设计,可以使图书管理系统更加稳定、可靠和高效。
七、实验总结与体会
历经大概一周的时间,我完成了本次图书管理系统数据库设计实验。从需求分析,到概念模型设计,到逻辑设计,再到最后的的物理设计过程。
首先查看本次数据库设计的文件结构
图7-1 数据库结构
本次实验创建了八个表,除了用户信息表在实验拓展中补充设计和利用,其他表均是本次设计的核心及操作对象。
在对功能展示中,为了更好的观察多个表属性之间的关系及变化,我创建了三个视图。可以减少了查询的复杂性,提高了查询的效率。
在上述基础上,我创建了一些存储过程,包括实现图书借阅、图书归还、图书续借、图书预订(取消预订)功能的存储过程。还有一部分存储过程是用于管理员实现获取学生的借阅信息、归还信息、续借信息及预订信息的功能。
从需求分析出发,本系统的目标是建立一个高效、易用、安全可靠的图书管理数据库系统,基于MYSQL实现,通过与python进行交互实现学生和管理员的登录、注册、个人信息管理、图书预订、借阅、归还、信息查询等功能。
在概念模型设计过程中,我列出了实体及联系的关系模型,并画出了对应的局部E-R图,并在最后对其进行了合并和优化,得到了最后的全局E-R图,其有利于进行实体识别、关系建立、可视化设计、规则约束及数据库设计。
在逻辑设计过程中,我将概念模型设计中的E-R转换成了关系模式,同时对本次设计中出现的表的结构进行了设计。对于每个表的设计,我们对分析其是否符合第一范式、第二范式和第三范式的要求,同时均判断是否存在函数依赖关系。经分析,此次设计中的涉及每个表均符合范式要求,且无函数依赖关系。
对于物理设计,我首先完成了表的创建,并对表的结构进行了查询。按照要求对每个表进行了命名。此外,我还对每个表基于键码建立了索引,提高了数据库的查询功能。
最后是核心的数据库功能设计阶段,先进行数据初始化过程,通过insert语句,事先导入若干学生、图书及管理员的信息 。在事务执行阶段,对于学生端,我依次完成了图书借阅、续借、归还及预订功能。对于管理员端,我完成了学生及图书信息的调整。并按照要求完成了对借阅信息和归还信息的查询。
在按要求实现给定功能的基础上,我对实验进行了拓展,即将MYSQL与PYTHON进行交互,更好的实现了数据库系统中的各种功能设计。关键之处就在于其可以实现用户输入数据,可以更人性化的对功能进行改进。另外一个亮点是通过调用python中的tkinter库,将功能选择与图形界面进行了结合,使整体运行界面变得更美观、更贴近用户现实需求。
总之,本次实验很好的完成了图书管理系统数据库的设计,过程中遇到的问题通过查阅资料自我思考和向老师请教等方式都得到了解决。通过本次实验,我对数据库设计的全过程有了更深的理解,对课堂上学到的理论知识也有了新的认识。这是一次很难忘和宝贵的实践经历!!!