1. 项目概述
这个基于MySQL的图书管理系统使用C语言开发,实现了图书管理、用户管理、借阅管理等核心功能。系统采用客户端-服务器架构,通过MySQL C Connector与数据库交互,适合作为中小型图书馆或书店的管理工具。
提示:本项目完整代码已开源,可直接用于学习或二次开发。建议在Visual Studio 2022环境下运行,兼容MySQL 5.7及以上版本。
2. 数据库设计
2.1 表结构设计
系统包含4个核心数据表:
-
管理员表(manager)
sql复制CREATE TABLE manager( M_ID INT PRIMARY KEY, M_Account VARCHAR(30) NOT NULL, M_Password VARCHAR(30) NOT NULL ); -
图书表(book)
sql复制CREATE TABLE book( B_ID INT PRIMARY KEY, B_NAME VARCHAR(30) NOT NULL, Author VARCHAR(30) NOT NULL, Publish VARCHAR(30) NOT NULL, Price DECIMAL(10,2) NOT NULL, Quantity INT DEFAULT 0 ); -
用户表(user)
sql复制CREATE TABLE user( U_ID INT PRIMARY KEY, U_Account VARCHAR(30) NOT NULL, U_Password VARCHAR(30) NOT NULL ); -
借阅表(borrow_book)
sql复制CREATE TABLE borrow_book( U_ID INT NOT NULL, B_ID INT NOT NULL, Borrow_time VARCHAR(30) NOT NULL, Return_time VARCHAR(30), State VARCHAR(30), PRIMARY KEY (U_ID,B_ID), FOREIGN KEY(U_ID) REFERENCES user(U_ID) ON DELETE CASCADE, FOREIGN KEY(B_ID) REFERENCES book(B_ID) ON DELETE CASCADE );
2.2 数据结构映射
在C程序中,使用链表结构存储表数据:
c复制typedef struct book_table {
int B_ID;
char B_NAME[30];
char Author[30];
char Publish[30];
float Price;
int Quantity;
struct book_table* next;
} book;
注意:Price字段在MySQL中使用DECIMAL(10,2),在C中使用float类型存储。实际商业项目中建议使用定点数类型处理金额。
3. 开发环境配置
3.1 必要组件
- MySQL Server:建议8.0+版本
- MySQL C Connector:libmysql.dll和头文件
- 开发工具:Visual Studio 2022
3.2 详细配置步骤
-
包含目录设置
- 项目属性 → C/C++ → 常规 → 附加包含目录
- 添加MySQL安装目录下的include文件夹路径
-
库目录设置
- 链接器 → 常规 → 附加库目录
- 添加MySQL安装目录下的lib文件夹路径
-
依赖项配置
- 链接器 → 输入 → 附加依赖项
- 添加
libmysql.lib
-
DLL文件部署
- 将
libmysql.dll复制到项目生成目录(x64/Debug或x64/Release)
- 将
常见问题:若出现LNK2019错误,请检查:
- 包含路径是否正确
- 库文件版本是否匹配
- 运行平台是否一致(x64/x86)
4. 核心功能实现
4.1 数据库连接
建立数据库连接的基础代码:
c复制MYSQL* con = mysql_init(NULL);
mysql_options(con, MYSQL_SET_CHARSET_NAME, "GBK");
if (!mysql_real_connect(con, "localhost", "root", "password",
"library_db", 3306, NULL, 0)) {
fprintf(stderr, "连接失败: %s\n", mysql_error(con));
return -1;
}
安全建议:实际项目中应将数据库密码加密存储,避免硬编码
4.2 数据加载与同步
从数据库加载数据到链表的典型实现:
c复制book* load_Book(book* head, MYSQL* mysql) {
MYSQL_RES* res = NULL;
MYSQL_ROW row;
mysql_query(mysql, "SELECT * FROM book;");
res = mysql_store_result(mysql);
while ((row = mysql_fetch_row(res))) {
book* new_node = (book*)malloc(sizeof(book));
// 数据填充...
new_node->next = NULL;
if (!head) head = new_node;
else {
book* p = head;
while (p->next) p = p->next;
p->next = new_node;
}
}
mysql_free_result(res);
return head;
}
4.3 图书管理功能
4.3.1 添加图书
c复制book* Add_new_book(book* head, MYSQL* mysql) {
book* newbook = (book*)malloc(sizeof(book));
// 输入验证...
char sql[256];
sprintf(sql, "INSERT INTO book VALUES('%d','%s','%s','%s','%f','%d')",
newbook->B_ID, newbook->B_NAME, newbook->Author,
newbook->Publish, newbook->Price, newbook->Quantity);
if (mysql_query(mysql, sql)) {
printf("添加失败: %s\n", mysql_error(mysql));
free(newbook);
return head;
}
// 链表操作...
return head;
}
4.3.2 图书查询
支持按书名、作者、出版社多条件查询:
c复制void Search_book(book* head) {
char search[100];
int option;
printf("请选择查询条件:\n");
printf("1. 书名\n2. 作者\n3. 出版社\n");
scanf("%d", &option);
printf("输入查询关键词: ");
scanf("%s", search);
book* p = head;
while (p) {
int match = 0;
switch(option) {
case 1: match = strstr(p->B_NAME, search) != NULL; break;
case 2: match = strstr(p->Author, search) != NULL; break;
case 3: match = strstr(p->Publish, search) != NULL; break;
}
if (match) {
// 显示匹配结果
}
p = p->next;
}
}
4.4 用户管理
4.4.1 用户登录
c复制user* user_Login(user* head) {
char account[30], password[30];
printf("请输入账号: ");
scanf("%s", account);
user* p = head;
while (p && strcmp(p->U_Account, account))
p = p->next;
if (!p) {
printf("账号不存在!\n");
return NULL;
}
int attempts = 3;
while (attempts--) {
printf("请输入密码: ");
scanf("%s", password);
if (!strcmp(password, p->U_Password)) {
printf("登录成功!\n");
return p;
}
printf("密码错误,剩余尝试次数: %d\n", attempts);
}
printf("登录失败!\n");
return NULL;
}
4.4.2 密码修改
c复制int Change_User_password(user* head, MYSQL* mysql) {
char account[30], old_pwd[30], new_pwd[30];
printf("请输入账号: ");
scanf("%s", account);
user* p = head;
while (p && strcmp(p->U_Account, account))
p = p->next;
if (!p) {
printf("用户不存在!\n");
return -1;
}
printf("请输入旧密码: ");
scanf("%s", old_pwd);
if (strcmp(old_pwd, p->U_Password)) {
printf("旧密码错误!\n");
return -1;
}
printf("请输入新密码: ");
scanf("%s", new_pwd);
char sql[256];
sprintf(sql, "UPDATE user SET U_Password='%s' WHERE U_Account='%s'",
new_pwd, account);
if (mysql_query(mysql, sql)) {
printf("修改失败: %s\n", mysql_error(mysql));
return -1;
}
strcpy(p->U_Password, new_pwd);
printf("密码修改成功!\n");
return 0;
}
4.5 借阅管理
4.5.1 图书借阅
c复制int borrow_book(int user_id, MYSQL* mysql, book* head) {
int book_id;
printf("请输入要借阅的图书编号: ");
scanf("%d", &book_id);
// 检查图书是否存在且有余量
book* p = head;
while (p && p->B_ID != book_id) p = p->next;
if (!p) {
printf("图书不存在!\n");
return -1;
}
if (p->Quantity <= 0) {
printf("该图书已无库存!\n");
return -1;
}
// 获取当前日期
time_t now = time(NULL);
struct tm* tm_info = localtime(&now);
char borrow_date[11];
strftime(borrow_date, 11, "%Y-%m-%d", tm_info);
// 执行借阅操作
char sql[256];
sprintf(sql, "INSERT INTO borrow_book VALUES(%d,%d,'%s',NULL,'BORROWED')",
user_id, book_id, borrow_date);
if (mysql_query(mysql, sql)) {
printf("借阅失败: %s\n", mysql_error(mysql));
return -1;
}
// 更新库存
sprintf(sql, "UPDATE book SET Quantity=Quantity-1 WHERE B_ID=%d", book_id);
mysql_query(mysql, sql);
printf("借阅成功!\n");
return 0;
}
4.5.2 图书归还
c复制int return_book(int user_id, MYSQL* mysql, book* head) {
int book_id;
printf("请输入要归还的图书编号: ");
scanf("%d", &book_id);
// 检查借阅记录是否存在
char sql[256];
sprintf(sql, "SELECT * FROM borrow_book WHERE U_ID=%d AND B_ID=%d AND State='BORROWED'",
user_id, book_id);
mysql_query(mysql, sql);
MYSQL_RES* res = mysql_store_result(mysql);
if (!mysql_num_rows(res)) {
printf("未找到该借阅记录!\n");
mysql_free_result(res);
return -1;
}
mysql_free_result(res);
// 获取当前日期
time_t now = time(NULL);
struct tm* tm_info = localtime(&now);
char return_date[11];
strftime(return_date, 11, "%Y-%m-%d", tm_info);
// 执行归还操作
sprintf(sql, "UPDATE borrow_book SET Return_time='%s', State='RETURNED' WHERE U_ID=%d AND B_ID=%d",
return_date, user_id, book_id);
if (mysql_query(mysql, sql)) {
printf("归还失败: %s\n", mysql_error(mysql));
return -1;
}
// 恢复库存
sprintf(sql, "UPDATE book SET Quantity=Quantity+1 WHERE B_ID=%d", book_id);
mysql_query(mysql, sql);
printf("归还成功!\n");
return 0;
}
5. 系统界面设计
5.1 主菜单
c复制void Menu() {
printf("\n***************************************\n");
printf("* 欢迎进入线上图书管理系统! *\n");
printf("* *\n");
printf("* 1.管理员登录 *\n");
printf("* 2.读者登录 *\n");
printf("* 3.读者注册 *\n");
printf("* 0.退出本系统 *\n");
printf("***************************************\n");
}
5.2 管理员菜单
c复制void manager_Menu() {
printf("\n***************************************\n");
printf("* 欢迎你,管理员 *\n");
printf("* *\n");
printf("* 1.添加书籍 *\n");
printf("* 2.显示书籍 *\n");
printf("* 3.查找书籍 *\n");
printf("* 4.修改书籍 *\n");
printf("* 5.删除书籍 *\n");
printf("* 6.显示用户数据 *\n");
printf("* 7.添加新管理员 *\n");
printf("* 0.退出系统 *\n");
printf("***************************************\n");
}
5.3 读者菜单
c复制void reader_Menu() {
printf("\n***************************************\n");
printf("* 欢迎你,读者 *\n");
printf("* *\n");
printf("* 1.借阅书籍 *\n");
printf("* 2.归还书籍 *\n");
printf("* 3.修改密码 *\n");
printf("* 0.退出系统 *\n");
printf("***************************************\n");
}
6. 项目优化建议
6.1 安全性增强
- 密码加密:使用SHA-256等算法加密存储密码
- SQL注入防护:使用预处理语句替代字符串拼接
- 输入验证:对所有用户输入进行严格验证
6.2 功能扩展
- 图书分类:增加分类管理功能
- 借阅统计:生成借阅报表和统计图表
- 逾期处理:实现逾期提醒和罚款计算
6.3 性能优化
- 连接池:实现数据库连接池管理
- 索引优化:为常用查询字段添加索引
- 缓存机制:对热点数据实施缓存
7. 常见问题解决
7.1 连接失败问题
问题现象:mysql_real_connect返回NULL
排查步骤:
- 检查MySQL服务是否运行
- 验证连接参数(主机名、端口、用户名、密码)
- 检查网络连接和防火墙设置
- 确认用户有访问指定数据库的权限
7.2 中文乱码问题
解决方案:
- 设置连接字符集为UTF-8或GBK
c复制mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4"); - 确保数据库、表和字段使用一致的字符集
- 检查客户端终端的字符编码设置
7.3 内存泄漏问题
预防措施:
- 为每个
malloc配对的free - 释放MySQL查询结果集
c复制MYSQL_RES* res = mysql_store_result(conn); // 使用res... mysql_free_result(res); - 关闭数据库连接
c复制
mysql_close(conn);
8. 项目部署指南
8.1 数据库准备
-
创建数据库和用户:
sql复制CREATE DATABASE library_db; CREATE USER 'lib_user'@'localhost' IDENTIFIED BY 'secure_password'; GRANT ALL PRIVILEGES ON library_db.* TO 'lib_user'@'localhost'; FLUSH PRIVILEGES; -
执行提供的SQL脚本创建表结构
8.2 程序编译
- 使用Visual Studio打开项目
- 配置包含路径和库路径
- 设置字符集为"使用多字节字符集"
- 编译生成可执行文件
8.3 运行环境
- 将
libmysql.dll放置在可执行文件同级目录 - 确保MySQL服务正常运行
- 根据需要修改数据库连接参数
9. 开发心得
在实际开发过程中,有几个关键点值得注意:
-
错误处理:MySQL API调用后应检查返回值,使用
mysql_error()获取详细错误信息 -
资源管理:数据库连接、查询结果集等都是需要手动释放的资源,必须确保正确释放
-
事务处理:对于借阅/归还等需要多个SQL语句的操作,应该使用事务保证数据一致性
-
性能考量:频繁的数据库操作会影响性能,合理使用本地缓存可以减少数据库访问
这个项目完整展示了如何使用C语言结合MySQL开发实际应用系统,涵盖了从数据库设计到界面实现的全过程,可以作为学习数据库编程的典型案例。