【实战分享】 从零搭建Python图书管理系统:python+MySQL实现完整业务流程(文末附全部源代码)

【实战分享】 从零搭建Python图书管理系统:python+MySQL实现完整业务流程(文末附全部源代码)

今天将基于Python的Tkinter框架(GUI)和MySQL数据库,搭建一个功能完整、界面友好的图书管理系统,实现图书管理、借阅流程、统计分析等核心功能。本文会在原有讲解基础上,嵌入核心代码片段,帮助大家更好地理解和复用。

一、系统整体架构设计

本次搭建的图书管理系统采用分层架构设计,将业务逻辑与界面展示、数据存储解耦,提高代码的可维护性和扩展性,整体架构分为三层:

  1. 数据层:由DatabaseManager类负责,处理与MySQL数据库的连接、表结构初始化、SQL执行等底层操作,屏蔽数据库操作的复杂性。
  2. 业务逻辑层:由BookManager类负责,封装图书添加、修改、删除、借阅、归还、统计等核心业务逻辑,提供统一的业务接口给上层调用。
  3. 界面层:由LibraryApp类负责,基于Tkinter构建可视化GUI界面,处理用户交互事件,调用业务逻辑层接口完成功能展

二、核心技术栈说明

  1. GUI框架:Tkinter(Python内置,无需额外配置)
  2. 数据库驱动:PyMySQL(连接MySQL的主流驱动)
  3. 数据库:MySQL 8.0+(持久化存储数据)

依赖安装代码

pip install pymysql 

三、核心功能模块详解(精简核心代码)

(一)数据库管理模块(DatabaseManager)

核心功能:自动创建数据库/表、统一SQL执行、连接管理,精简代码如下:

import pymysql classDatabaseManager:def__init__(self, config): self.config = config self.conn = self._create_connection() self._init_tables()def_create_connection(self):"""自动创建数据库并建立连接"""# 先创建数据库 temp_conn = pymysql.connect(**{ k:v for k,v in self.config.items()if k!='database'})with temp_conn.cursor()as cur: cur.execute(f"CREATE DATABASE IF NOT EXISTS { self.config['database']} DEFAULT CHARSET utf8mb4") temp_conn.close()# 连接目标数据库return pymysql.connect(**self.config)def_init_tables(self):"""初始化图书表和借阅记录表"""with self.conn.cursor()as cur:# 图书表 cur.execute("""CREATE TABLE IF NOT EXISTS books ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, author VARCHAR(100) NOT NULL, isbn VARCHAR(20) UNIQUE, stock INT DEFAULT 0, available INT DEFAULT 0 )""")# 借阅记录表 cur.execute("""CREATE TABLE IF NOT EXISTS borrow_records ( id INT AUTO_INCREMENT PRIMARY KEY, book_id INT NOT NULL, borrower_name VARCHAR(50) NOT NULL, FOREIGN KEY (book_id) REFERENCES books(id) )""") self.conn.commit()defexecute(self, sql, params=(), fetch=False):"""统一执行SQL"""with self.conn.cursor()as cur: cur.execute(sql, params)if fetch:return cur.fetchall() self.conn.commit()

(二)图书业务管理模块(BookManager)

核心功能:图书增删、借阅归还,精简核心代码如下:

在这里插入图片描述
from datetime import datetime, timedelta classBookManager:def__init__(self, db): self.db = db defadd_book(self, title, author, isbn, stock=1):"""添加图书""" sql ="INSERT INTO books (title, author, isbn, stock, available) VALUES (%s,%s,%s,%s,%s)" self.db.execute(sql,(title, author, isbn, stock, stock))defborrow_book(self, book_id, borrower_name):"""借书:校验库存+更新可借数量+生成记录"""# 校验可借数量 book = self.db.execute("SELECT available FROM books WHERE id=%s",(book_id,), fetch=True)ifnot book or book[0][0]<=0:returnFalse# 生成借阅记录 borrow_date = datetime.now().date() return_date = borrow_date + timedelta(days=30) self.db.execute("INSERT INTO borrow_records (book_id, borrower_name, borrow_date, return_date) VALUES (%s,%s,%s,%s)",(book_id, borrower_name, borrow_date, return_date))# 更新可借数量 self.db.execute("UPDATE books SET available = available -1 WHERE id=%s",(book_id,))returnTruedefreturn_book(self, record_id):"""还书:更新状态+恢复可借数量"""# 获取图书ID book_id = self.db.execute("SELECT book_id FROM borrow_records WHERE id=%s",(record_id,), fetch=True)[0][0]# 更新借阅状态 self.db.execute("UPDATE borrow_records SET status='已还', actual_return_date=%s WHERE id=%s",(datetime.now().date(), record_id))# 恢复可借数量 self.db.execute("UPDATE books SET available = available +1 WHERE id=%s",(book_id,))returnTrue

(三)GUI界面模块(LibraryApp)

核心功能:搭建三大标签页(图书管理、借阅管理、统计分析),精简核心代码如下:

import tkinter as tk from tkinter import ttk, messagebox classLibraryApp:def__init__(self, root): self.root = root self.root.title("图书管理系统") self.root.geometry("1000x700")# 初始化数据库 self.db_config ={ "host":"localhost","user":"root","password":"root","database":"library_system"} self.db = DatabaseManager(self.db_config) self.book_manager = BookManager(self.db)# 搭建标签页 self.notebook = ttk.Notebook(root) self.notebook.pack(fill="both", expand=True)# 三个核心标签页 ttk.Frame(self.notebook, name="book_frame") ttk.Frame(self.notebook, name="borrow_frame") ttk.Frame(self.notebook, name="stats_frame") self.notebook.add(self.root.nametowidget("book_frame"), text="图书管理") self.notebook.add(self.root.nametowidget("borrow_frame"), text="借阅管理") self.notebook.add(self.root.nametowidget("stats_frame"), text="统计分析")# 图书管理界面(精简版) self._setup_book_ui()def_setup_book_ui(self):"""图书管理界面:搜索+列表+添加按钮""" frame = self.root.nametowidget("book_frame")# 搜索框 tk.Entry(frame, name="search_entry").pack(fill="x", padx=10, pady=5)# 图书列表 tree = ttk.Treeview(frame, columns=("ID","书名","作者"), show="headings") tree.heading("ID", text="ID") tree.heading("书名", text="书名") tree.heading("作者", text="作者") tree.pack(fill="both", expand=True, padx=10, pady=5)# 添加按钮 tk.Button(frame, text="添加图书", command=self._show_add_book).pack(pady=5)def_show_add_book(self):"""显示添加图书弹窗(简易版)"""# 此处省略表单细节,核心是调用book_manager.add_book messagebox.showinfo("提示","打开添加图书表单")

主函数(程序启动)

defmain(): root = tk.Tk() LibraryApp(root) root.mainloop()if __name__ =="__main__": main()

四、系统核心特性

  1. 高可用性:自动建库建表,首次启动即可使用
  2. 数据一致性:借阅/归还自动同步可借数量,避免数据混乱
  3. 操作友好:界面布局清晰,关键操作有提示
  4. 可扩展性强:分层架构,便于后续扩展功能

五、系统运行步骤

  1. 环境准备:安装Python 3.8+、PyMySQL、启动MySQL服务
  2. 配置修改:修改db_config中的MySQL密码
  3. 启动程序:直接运行代码,自动创建数据库和表
  4. 功能使用:进行图书添加、借阅、归还等操作

本系统基于Python 和MySQL,以精简代码实现了图书管理核心功能,采用分层架构设计,代码简洁易懂、可复用性强。既可以作为Python GUI和数据库操作的实战案例,也可根据实际需求快速二次开发,适用于小型图书馆、图书角等场景。

六、全部实现源代码

  1. 创建数据库
-- 创建数据库 CREATE DATABASE IF NOT EXISTS library_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 使用数据库 USE library_system; 

程序会自动创建表结构,无需手动建表

  1. 修改数据库配置
    在代码中修改这部分配置:
self.db_config ={ "host":"localhost",# 数据库主机"user":"root",# 数据库用户名"password":"your_password",# 你的数据库密码,按照自己的MySQL数据用户名和密码填写"database":"library_system",# 数据库名称"port":3306,# 端口号"charset":"utf8mb4",# 字符集}
  1. 全部程序源代码:
import tkinter as tk from tkinter import messagebox, ttk from datetime import datetime, timedelta import pymysql from typing import Dict, List, Optional, Tuple from dataclasses import dataclass import threading @dataclassclassBook:"""图书数据类"""id: Optional[int]=None title:str="" author:str="" isbn:str="" category:str="" publisher:str="" publish_date:str="" price:float=0.0 stock:int=0 available:int=0 status:str="正常"@dataclassclassBorrowRecord:"""借阅记录数据类"""id: Optional[int]=None book_id:int=0 book_title:str="" borrower_name:str="" borrower_phone:str="" borrow_date:str="" return_date:str="" actual_return_date:str="" status:str="借出"classDatabaseManager:"""数据库管理类"""def__init__(self, config: Dict): self.config = config self.conn =None self.ensure_connection() self.init_database()defensure_connection(self)->None:"""确保数据库连接"""try:if self.conn and self.conn.open:try: self.conn.ping(reconnect=False)returnexcept:passexcept:passtry:# 先连接到MySQL,如果数据库不存在则创建 temp_config = self.config.copy() database = temp_config.pop('database')# 先用默认数据库连接,创建目标数据库 temp_config['database']='mysql' temp_conn = pymysql.connect(**temp_config)with temp_conn.cursor()as cursor: cursor.execute(f"CREATE DATABASE IF NOT EXISTS { database} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci") temp_conn.commit() temp_conn.close()# 现在用真实的配置连接 self.config['database']= database self.conn = pymysql.connect(**self.config)print("数据库连接成功")except Exception as e:print(f"数据库连接失败: { e}")raisedefinit_database(self)->None:"""初始化数据库表"""try:with self.conn.cursor()as cursor:# 先删除旧表(可选,用于完全重置)# cursor.execute("DROP TABLE IF EXISTS borrow_records")# cursor.execute("DROP TABLE IF EXISTS books")# cursor.execute("DROP TABLE IF EXISTS categories")# 创建图书表 cursor.execute(""" CREATE TABLE IF NOT EXISTS books ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, author VARCHAR(100) NOT NULL, isbn VARCHAR(20) UNIQUE KEY, category VARCHAR(50) NOT NULL, publisher VARCHAR(100), publish_date DATE, price DECIMAL(10,2) DEFAULT 0.00, stock INT DEFAULT 0, available INT DEFAULT 0, status VARCHAR(20) DEFAULT '正常', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_category (category), INDEX idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci """)print("图书表创建成功")# 创建借阅记录表 cursor.execute(""" CREATE TABLE IF NOT EXISTS borrow_records ( id INT AUTO_INCREMENT PRIMARY KEY, book_id INT NOT NULL, borrower_name VARCHAR(50) NOT NULL, borrower_phone VARCHAR(20), borrow_date DATE NOT NULL, return_date DATE NOT NULL, actual_return_date DATE, status VARCHAR(20) DEFAULT '借出', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (book_id) REFERENCES books(id) ON DELETE CASCADE, INDEX idx_book_id (book_id), INDEX idx_status (status), INDEX idx_borrower (borrower_name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci """)print("借阅记录表创建成功")# 创建图书分类表 cursor.execute(""" CREATE TABLE IF NOT EXISTS categories ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_name (name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci """)print("分类表创建成功") self.conn.commit() self.init_sample_data()print("数据库表初始化完成")except pymysql.err.ProgrammingError as e:if"already exists"instr(e):print("表已存在,跳过创建") self.init_sample_data()else:print(f"数据库初始化失败: { e}")raiseexcept Exception as e:print(f"数据库初始化失败: { e}")raisedefinit_sample_data(self)->None:"""初始化示例数据"""try:with self.conn.cursor()as cursor:# 检查是否已有数据 cursor.execute("SELECT COUNT(*) FROM books")if cursor.fetchone()[0]>0:print("示例数据已存在,跳过初始化")return# 初始化分类 categories =["计算机科学","文学","历史","哲学","数学","物理","化学","生物","经济学","管理学"]for category in categories:try: cursor.execute("INSERT INTO categories (name) VALUES (%s)",(category,))except pymysql.err.IntegrityError:pass# 分类已存在# 初始化图书数据 books =[("Python编程从入门到实践","埃里克·马瑟斯","9787115428028","计算机科学","人民邮电出版社","2016-07-01",89.00,5),("算法导论","Thomas H. Cormen","9787111407010","计算机科学","机械工业出版社","2012-12-01",128.00,3),("深度学习","Ian Goodfellow","9787115461476","计算机科学","人民邮电出版社","2017-07-01",168.00,2),("JavaScript高级程序设计","Matt Frisbie","9787115583864","计算机科学","人民邮电出版社","2020-09-01",139.00,4),("设计模式","Gang of Four","9787111075776","计算机科学","机械工业出版社","2000-09-01",45.00,3),("红楼梦","曹雪芹","9787020002207","文学","人民文学出版社","1996-12-01",39.50,10),("三国演义","罗贯中","9787020008735"

Read more

【C++】深入浅出“图”——最短路径算法

【C++】深入浅出“图”——最短路径算法

文章目录 * 一、Dijkstra算法 * 二、Bellman_Ford算法 * 三、Floyd_Warshall算法 一、Dijkstra算法 最短路径问题是指,从在带权的有向图中从某一顶点出发,找到通往另一顶点的最短路径,“最短”指的是沿路径各边的权值总和最小。 Dijkstra算法是单源最短路径的经典贪心算法,只能用于没有负权的图。它从起点出发,每次选当前距离最小且未确定最短路径的节点,用它去松弛(更新)所有邻接点的最短路径估计值,标记该节点为 “已确定”,重复此过程直到所有节点处理完毕,最终得到起点到图中所有节点的最短路径。 // src是选定的起点,dist记录起点到各点的最短路径,pPath记录到每个点的最短路径的前驱顶点下标voidDijkstra(const V& src, vector<W>& dist, vector<int>& pPath){ size_t srci =GetVertexIndex(

By Ne0inhk
【Linux】线程池(一)C++ 手写线程池:基于策略模式实现高性能日志模块

【Linux】线程池(一)C++ 手写线程池:基于策略模式实现高性能日志模块

文章目录 * 池化技术 * 线程池的日志模块 * 日志与策略模式 * 日志模块 * 两个核心问题 * 设计文件等级 * 刷新策略 * 获取日志时间 * logger类实现 * 内部类LogMessage实现 * 日志刷新流程图及源码 池化技术 池化技术可以减少很多的底层重复工作,例如创建进程、线程、申请内存空间时的系统调用和初始化工作,例如线程池,先预先创建好一些线程,当任务到来时直接将预先创建好的线程唤醒去处理任务,效率会远远高于任务到来时临时创建线程。例如内存池,但我们要用1mb空间时内存池会一次性申请20mb空间,效率会远远高于用多少空间申请多少空间(申请空间会调用系统调用)。 线程池是执行流级别的池化技术,STL中的空间配置器和内存池是内存块管理级别的池化技术。 线程池的日志模块 下⾯开始,我们结合我们之前所做的所有封装,进⾏⼀个线程池的设计。在写之前,我们要做如下准备。 * 准备线程的封装 * 准备锁和条件变量的封装 * 引⼊日志,对线程进⾏封装 日志与策略

By Ne0inhk
【探寻C++之旅】C++ 智能指针完全指南:从原理到实战,彻底告别内存泄漏

【探寻C++之旅】C++ 智能指针完全指南:从原理到实战,彻底告别内存泄漏

前言 作为 C++ 开发者,你是否曾因以下场景头疼不已?函数中new了数组,却因异常抛出导致后续delete没执行,排查半天定位到内存泄漏;多模块共享一块内存,不知道该由谁负责释放,最后要么重复释放崩溃,要么漏释放泄漏;用了auto_ptr后,拷贝对象导致原对象 “悬空”,访问时直接崩溃却找不到原因。 如果你有过这些经历,那智能指针一定是你必须掌握的现代 C++ 工具。它基于 RAII 思想,自动管理动态资源,让你无需手动delete,从根源上减少内存泄漏风险。今天,我们就从 “为什么需要智能指针” 到 “不同智能指针的实战场景”,带你系统掌握这一核心特性。 请君浏览 * 前言 * 一、智能指针的诞生:解决手动管理内存的 “千古难题” * 1.1 一个典型的内存泄露场景 * 1.2 智能指针的核心:RAII 思想 * 二、C++ 标准库智能指针:

By Ne0inhk
【C++模版】泛型编程:代码复用的终极利器

【C++模版】泛型编程:代码复用的终极利器

目录 一、泛型编程 1.1 为什么需要泛型编程? 1.2 模板:泛型编程的基础 二、函数模板 2.1 函数模板的定义格式 2.2 函数模板的原理 2.3 函数模板的实例化 2.3.1 隐式实例化 2.3.2 显式实例化 2.4 模板参数的匹配原则 ☃. 小彩蛋: 模板中::的二义性问题 三、类模板 3.1 类模板的定义格式 3.2 类模板的实例化 四、非类型模板参数  4.1 核心概念与语法 经典案例:实现编译期定长数组

By Ne0inhk