Python+MySQL图书馆管理系统开发实战指南

发布时间:2026/10/12 5:53:53
Python+MySQL图书馆管理系统开发实战指南 简介这是一套基于Python与MySQL开发的图形化界面图书馆管理系统源码面向Python初学者与数据库应用开发者解决图书信息管理、读者资料维护及借阅流程自动化等实际业务问题适用于课程设计、毕业设计或小型机构内部管理系统搭建。资源包共222个文件9.53MB包含13个核心Python脚本含GUI逻辑与数据库交互、75个GIF动图用于界面交互演示、37个JS与26个HTML文件构成前端管理界面、20个JPG与4个PNG素材以及CSS、字体文件等配套资源整体采用BootstrapLayui前端框架构建响应式界面。已有3427人学习下载提供完整可运行工程结构、清晰模块划分图书/读者/借阅/权限管理、MySQL建表语句与连接配置示例以及含错误处理、日志记录和基础报表功能的实战代码助读者快速掌握GUI开发、数据库CRUD操作与前后端协同实践。1. 为什么一个“PythonMySQL图形化界面图书馆管理系统”能成为新手练手的黄金项目你刚学完 Python 基础、写过几个print(Hello World)和for i in range(10)也装好了 MySQL但卡在「不知道下一步该做什么」——这时候一个带完整 GUI 界面、真实数据库交互、增删改查全链路闭环的「图书馆管理系统」源码包就是最不玄学的跃迁跳板。它不是玩具计算器也不是空跑的 ORM 示例它真要录入图书 ISBN、按作者模糊检索、处理借阅状态变更、防止同一本书被重复借出、还要把操作日志写进 MySQL 表里。所有模块都可触摸、可打断点、可改字段名、可换图标——GUI 是 tkinter 还是 PyQt5数据库连接要不要加连接池借书时怎么用事务锁住库存这些都不是理论题而是你双击.py文件后立刻会撞上的墙。适合刚写完《Python 编程从入门到实践》第 12 章、正犹豫该啃 Django 还是先打牢桌面端基础的开发者也适合高校课程设计需要交可运行 demo 的学生——它不依赖云服务、不调外部 API、不涉及用户认证黑盒所有逻辑都在本地跑通部署只要一台装了 Python 3.8 和 MySQL 5.7/8.0 的 Windows 或 Linux 机器。我带过的 17 届毕设学生里有 6 人靠这个项目框架改出「实验室设备管理系统」「社区图书角登记平台」「中小学教辅资料库」核心就三点表结构清晰、GUI 控件与数据库字段一一映射、业务逻辑没堆屎山。2. 从零搭建环境Python、MySQL、GUI 库三件套的最小可行安装路径2.1 Python 版本选型与虚拟环境隔离为什么必须用 3.8图书馆系统源码中大量使用f-string、dataclass、typing.Literal等语法特性Python 3.7 是底线但 3.8 才真正稳定支持asyncio.run()后续可能扩展扫码借阅异步接口而 3.9 的graphlib.TopologicalSorter在构建图书分类依赖图时能省 80 行代码。不要用系统自带 Python——尤其 macOS 和某些 Linux 发行版预装的 Python 2.7 或 3.6极易因pip install权限问题或ssl模块缺失导致 MySQL 驱动安装失败。正确做法是# Windows 用户直接去 python.org 下载 Python 3.10.12非最新版因部分 tkinter 主题控件在 3.11 有渲染偏移 # Linux/macOS 用户用 pyenv 管理多版本避免污染系统 Python curl https://pyenv.run | bash # 将以下三行加入 ~/.bashrc 或 ~/.zshrc export PYENV_ROOT$HOME/.pyenv command -v pyenv /dev/null || export PATH$PYENV_ROOT/bin:$PATH eval $(pyenv init -) # 重载配置并安装指定版本 source ~/.bashrc pyenv install 3.10.12 pyenv global 3.10.12提示pyenv global后执行python --version必须返回3.10.12否则说明未生效。若报错SSL module not available是 OpenSSL 未正确链接需重装 Python 并指定--enable-optimizations参数具体命令见 pyenv 文档。2.2 MySQL 安装与初始化避开 root 密码失效、时区错误、严格模式三大坑很多同学卡在第一步pymysql.connect()报错Access denied for user rootlocalhost。这不是密码错了而是 MySQL 8.0 默认启用caching_sha2_password插件而旧版 PyMySQL 不兼容。解决方案不是降级 MySQL而是重置认证方式-- 登录 MySQL首次安装后默认无密码直接回车 mysql -u root -p -- 输入临时密码查看 /var/log/mysqld.log 中 generated password -- 执行以下 SQL注意必须用单引号包裹密码字符串 ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_secure_password; FLUSH PRIVILEGES;同时必须关闭严格模式否则插入空字符串到NOT NULL字段会直接报错而图书馆系统常有可选字段如“备注”# 编辑 MySQL 配置文件Linux: /etc/my.cnfWindows: C:\ProgramData\MySQL\MySQL Server 8.0\my.ini # 在 [mysqld] 段落下添加 sql_mode STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION # → 改为 sql_mode NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION重启 MySQL 后验证mysql -u root -p -e SELECT sql_mode; # 输出应不含 STRICT_TRANS_TABLES2.3 GUI 库选择tkinter 是唯一零依赖选项PyQt5 需额外编译但体验翻倍源码包里大概率用的是tkinterPython 自带但如果你打算长期维护或交付给非技术用户强烈建议切换为 PyQt5——它原生支持高 DPI 屏幕、可嵌入 Webview 显示图书封面、拖拽排序更流畅。安装命令差异巨大# tkinter无需安装但需确认 Tk 版本 ≥ 8.6否则 Treeview 表头排序失效 python -c import tkinter as tk; print(tk.TkVersion) # 应输出 8.6 # PyQt5必须用 pip 安装conda 会引入 Qt5 与系统冲突 pip install PyQt55.15.10 # 固定小版本5.15.11 在某些 Linux 发行版上崩溃 # 验证安装 python -c from PyQt5.QtWidgets import QApplication; print(OK)注意PyQt5 5.15.10 是最后一个支持 Python 3.10 的稳定版且对 Windows 10/11 兼容性最佳。若用 5.15.11启动时可能报QApplication: invalid style override passed这是 Qt 样式引擎 bug无解只能降级。3. 数据库建模实战从 ER 图到可执行 SQL绕开字符集、外键、时间戳三大雷区3.1 图书馆核心实体关系ER与字段语义设计一个能跑通借阅流程的最小表集合只有 4 张books图书主表、members读者表、borrow_records借阅记录、categories分类表。但新手常犯的错是照着 Excel 表头直接建字段比如book_name VARCHAR(100)—— 这会导致中文书名超长截断。实际字段设计必须考虑业务约束表名字段名类型约束说明booksisbnCHAR(13)PRIMARY KEY用 CHAR 固定长度比 VARCHAR 更快索引13 位 EAN-13 标准含 978 前缀bookstitleVARCHAR(200)NOT NULL书名最长可达 150 字如《四库全书总目提要补正全三册》booksauthorVARCHAR(100)DEFAULT 允许空因古籍常佚名borrow_recordsborrow_timeDATETIMEDEFAULT CURRENT_TIMESTAMP记录精确到秒借书即写入borrow_recordsreturn_timeDATETIMENULL归还时 UPDATENULL 表示未归还关键细节books.isbn必须设为CHAR(13)而非VARCHAR(13)因为 ISBN 是固定长度编码CHAR在 BTree 索引中比较更快borrow_records.return_time设为NULL而非0000-00-00 00:00:00后者在 MySQL 5.7 严格模式下非法。3.2 创建数据库与表的完整 SQL 脚本含字符集与排序规则直接复制粘贴以下脚本到 MySQL 命令行不要用 phpMyAdmin 等 GUI 工具导入——它们常自动添加AUTO_INCREMENT到不该加的字段-- 创建数据库显式指定字符集避免乱码 CREATE DATABASE IF NOT EXISTS library_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE library_db; -- 图书表 CREATE TABLE books ( isbn CHAR(13) PRIMARY KEY, title VARCHAR(200) NOT NULL, author VARCHAR(100) DEFAULT , publisher VARCHAR(100) DEFAULT , publish_year YEAR DEFAULT NULL, category_id INT DEFAULT NULL, stock INT DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; -- 读者表 CREATE TABLE members ( member_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, phone VARCHAR(20) UNIQUE, email VARCHAR(100) UNIQUE, register_date DATE DEFAULT (CURRENT_DATE) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; -- 借阅记录表核心必须用外键约束 CREATE TABLE borrow_records ( record_id INT PRIMARY KEY AUTO_INCREMENT, isbn CHAR(13) NOT NULL, member_id INT NOT NULL, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP, return_time DATETIME NULL, status ENUM(borrowed, returned, overdue) DEFAULT borrowed, FOREIGN KEY (isbn) REFERENCES books(isbn) ON DELETE CASCADE, FOREIGN KEY (member_id) REFERENCES members(member_id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; -- 分类表支持多级分类用 parentId 实现 CREATE TABLE categories ( category_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, parent_id INT DEFAULT NULL, level TINYINT DEFAULT 1, FOREIGN KEY (parent_id) REFERENCES categories(category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;3.3 初始化测试数据用 INSERT SELECT 替代逐条 INSERT提速 10 倍别手动敲 100 条INSERT INTO books ...——用INSERT ... SELECT一次性生成测试数据-- 插入 5 个常用分类 INSERT INTO categories (name, level) VALUES (文学, 1), (计算机, 1), (数学, 1), (历史, 1), (艺术, 1); -- 插入 20 本测试图书用 VALUES ROW 构造MySQL 8.0 支持 INSERT INTO books (isbn, title, author, publisher, publish_year, category_id, stock) VALUES ROW(9787536692930, 三体, 刘慈欣, 重庆出版社, 2008, 1, 5), ROW(9787020023539, 红楼梦, 曹雪芹, 人民文学出版社, 2008, 1, 3), ROW(9787302187431, 算法导论, Cormen, 清华大学出版社, 2009, 2, 8), ROW(9787040396621, 高等数学, 同济大学, 高等教育出版社, 2014, 3, 12);血泪经验INSERT ... VALUES ROW(...)比传统VALUES (...),(...)在批量插入时性能提升明显且语法更紧凑。若 MySQL 版本 8.0改用INSERT INTO books SELECT ... FROM (VALUES ...)结构。4. GUI 界面开发tkinter 与 PyQt5 的控件映射策略与事件绑定陷阱4.1 tkinter 版用ttk.Treeview实现图书列表解决列宽自适应与右键菜单缺失问题源码中常见Listbox显示图书但无法多列排序、不支持点击表头排序、不能右键操作。升级为ttk.Treeview是刚需import tkinter as tk from tkinter import ttk class BookListFrame(ttk.Frame): def __init__(self, parent): super().__init__(parent) # 创建 Treeview注意columns 是元组首元素是 #0 隐藏列 self.tree ttk.Treeview(self, columns(isbn, title, author, stock), showheadings) # 设置列标题和宽度关键不设 width 会导致列挤成一团 self.tree.heading(isbn, textISBN) self.tree.column(isbn, width120, anchorcenter) self.tree.heading(title, text书名) self.tree.column(title, width250, anchorw) self.tree.heading(author, text作者) self.tree.column(author, width150, anchorw) self.tree.heading(stock, text库存) self.tree.column(stock, width80, anchorcenter) # 绑定双击事件注意TreeviewSelect 是单击Double-1 是双击 self.tree.bind(Double-1, self.on_double_click) # 滚动条联动必须用 scrollbar.configure(command...) 而非 tree.configure(yscrollcommand...) scrollbar ttk.Scrollbar(self, orientvertical, commandself.tree.yview) self.tree.configure(yscrollcommandscrollbar.set) # 布局pack 顺序影响层级先 pack tree 再 pack scrollbar self.tree.pack(sidetk.LEFT, filltk.BOTH, expandTrue) scrollbar.pack(sidetk.RIGHT, filltk.Y) def on_double_click(self, event): # 获取选中行的值注意item() 返回字典values 是元组 selected_item self.tree.focus() if selected_item: values self.tree.item(selected_item)[values] print(f双击图书: {values[1]} (ISBN: {values[0]}))逻辑说明ttk.Treeview的column()方法中width单位是像素anchor控制对齐方式w左对齐center居中bind(Double-1)绑定鼠标左键双击比TreeviewSelect更符合用户直觉滚动条必须用commandself.tree.yview而非反向设置否则拖动无效。4.2 PyQt5 版用QTableViewQSqlTableModel实现零 SQL 查询但必须重写setData()处理外键PyQt5 的优势在于数据库模型自动绑定但QSqlTableModel默认不支持外键关联显示如books.category_id应显示为「计算机」而非数字 2。解决方案是继承并重写data()方法from PyQt5.QtSql import QSqlTableModel, QSqlQuery from PyQt5.QtCore import Qt class BookModel(QSqlTableModel): def __init__(self, db): super().__init__(dbdb) self.setTable(books) self.select() # 立即查询 def data(self, index, roleQt.DisplayRole): if not index.isValid(): return None # 重写 category_id 显示为分类名称 if index.column() 5 and role Qt.DisplayRole: # category_id 列索引为 5 cat_id super().data(index, Qt.EditRole) if cat_id: query QSqlQuery(self.db()) query.exec(fSELECT name FROM categories WHERE category_id {cat_id}) if query.next(): return query.value(0) return 未分类 return super().data(index, role) def setData(self, index, value, roleQt.EditRole): # 当编辑 category_id 列时将「计算机」转为对应 ID if index.column() 5 and role Qt.EditRole: cat_name str(value) query QSqlQuery(self.db()) query.exec(fSELECT category_id FROM categories WHERE name {cat_name}) if query.next(): value query.value(0) else: # 名称不存在则插入新分类 query.exec(fINSERT INTO categories (name) VALUES ({cat_name})) value query.lastInsertId() return super().setData(index, value, role)参数说明QSqlTableModel的data()方法在表格渲染时被频繁调用必须高效setData()是用户编辑单元格时触发此处将分类名称转为 ID 再存入数据库避免前端显示与后端存储不一致。4.3 避坑GUI 与数据库线程安全的 3 个致命错误现象点击「借书」按钮后界面卡死或 MySQL 报错Lost connection to MySQL server during query原因GUI 主线程直接执行耗时数据库操作如SELECT * FROM books WHERE title LIKE %Python%阻塞 UI 更新或多个线程共用同一pymysql.Connection对象解决永远不用主线程查数据库用threading.Thread或QTimer.singleShot(0, ...)将查询移到后台每个线程独占 Connection不要全局共享conn pymysql.connect(...)而是在函数内创建、用完立即conn.close()PyQt5 中禁止在子线程更新 UI必须用QMetaObject.invokeMethod()或信号槽机制self.data_ready.emit(rows)# 错误示范主线程阻塞 def search_books(self): conn get_db_connection() # 全局连接 cursor conn.cursor() cursor.execute(SELECT * FROM books WHERE title LIKE %s, (f%{self.search_input.text()}%,)) results cursor.fetchall() # 此处卡住 UI self.update_table(results) # 此处更新 UI # 正确做法PyQt5 class SearchWorker(QObject): data_ready pyqtSignal(list) def do_search(self, keyword): conn get_db_connection() # 每次新建连接 cursor conn.cursor() cursor.execute(SELECT * FROM books WHERE title LIKE %s, (f%{keyword}%,)) self.data_ready.emit(cursor.fetchall()) # 发射信号 conn.close() # 在主窗口中 self.worker SearchWorker() self.worker.data_ready.connect(self.update_table) QThread.currentThread().started.connect(lambda: self.worker.do_search(self.search_input.text()))5. 核心业务逻辑落地借阅、归还、库存同步的事务控制与并发安全5.1 借书操作的原子性保障用START TRANSACTIONSELECT ... FOR UPDATE锁定库存单纯UPDATE books SET stock stock - 1 WHERE isbn 978...在高并发下会超借——两个用户同时借同一本书库存从 1 减两次变成 -1。正确方案是def borrow_book(isbn: str, member_id: int) - bool: conn get_db_connection() try: with conn.cursor() as cursor: # 1. 开启事务 conn.begin() # 2. 用 SELECT ... FOR UPDATE 锁定该书记录防止其他事务修改 cursor.execute( SELECT stock FROM books WHERE isbn %s FOR UPDATE, (isbn,) ) result cursor.fetchone() if not result or result[0] 0: raise ValueError(库存不足) # 3. 插入借阅记录 cursor.execute( INSERT INTO borrow_records (isbn, member_id) VALUES (%s, %s), (isbn, member_id) ) # 4. 更新库存此时 stock 已被锁定不会并发冲突 cursor.execute( UPDATE books SET stock stock - 1 WHERE isbn %s, (isbn,) ) # 5. 提交事务 conn.commit() return True except Exception as e: conn.rollback() logging.error(f借书失败: {e}) return False finally: conn.close()关键参数FOR UPDATE是 InnoDB 行锁只锁住匹配的isbn行不影响其他图书操作conn.begin()显式开启事务避免隐式提交rollback()在异常时回滚保证数据一致性。5.2 归还操作的状态机校验防止重复归还、已归还图书再借出归还不是简单UPDATE borrow_records SET return_time NOW() WHERE ...必须校验业务状态def return_book(record_id: int) - bool: conn get_db_connection() try: with conn.cursor() as cursor: conn.begin() # 1. 查询当前记录状态必须用 FOR UPDATE 锁定该记录 cursor.execute( SELECT isbn, return_time FROM borrow_records WHERE record_id %s FOR UPDATE, (record_id,) ) row cursor.fetchone() if not row: raise ValueError(借阅记录不存在) if row[1] is not None: # return_time 不为空表示已归还 raise ValueError(该记录已归还不可重复操作) # 2. 更新归还时间 cursor.execute( UPDATE borrow_records SET return_time NOW(), status returned WHERE record_id %s, (record_id,) ) # 3. 库存 1注意这里必须用 isbn不能用 record_id 关联 cursor.execute( UPDATE books SET stock stock 1 WHERE isbn %s, (row[0],) ) conn.commit() return True except Exception as e: conn.rollback() logging.error(f归还失败: {e}) return False finally: conn.close()逻辑说明status字段用于前端状态过滤如只显示statusborrowed的待归还列表row[0]是isbn从borrow_records中取出后更新books.stock确保图书与借阅记录强关联。5.3 并发压力测试用locust模拟 50 用户同时借书验证锁机制有效性光看代码不够必须实测。用 Locust 写一个最简压测脚本# locustfile.py from locust import HttpUser, task, between import pymysql class LibraryUser(HttpUser): wait_time between(1, 3) def on_start(self): # 每个用户独享连接 self.conn pymysql.connect( host127.0.0.1, userroot, passwordyour_secure_password, databaselibrary_db ) task def borrow_random_book(self): cursor self.conn.cursor() # 随机取一本库存 0 的书 cursor.execute(SELECT isbn FROM books WHERE stock 0 ORDER BY RAND() LIMIT 1) isbn cursor.fetchone() if isbn: try: # 模拟借书事务复用上面的 borrow_book 逻辑 cursor.execute(START TRANSACTION) cursor.execute(SELECT stock FROM books WHERE isbn %s FOR UPDATE, (isbn[0],)) stock cursor.fetchone()[0] if stock 0: cursor.execute(INSERT INTO borrow_records (isbn, member_id) VALUES (%s, 1), (isbn[0],)) cursor.execute(UPDATE books SET stock stock - 1 WHERE isbn %s, (isbn[0],)) cursor.execute(COMMIT) else: cursor.execute(ROLLBACK) except Exception as e: cursor.execute(ROLLBACK) print(f借书失败: {e}) def on_stop(self): self.conn.close()运行命令locust -f locustfile.py --hosthttp://localhost:5000打开http://localhost:8089设置 50 用户、每秒 5 个请求——观察books.stock是否始终 ≥ 0且borrow_records数量与成功请求数一致。6. 部署与交付打包成单文件 exe/dmg绕过 DLL 丢失、字体缺失、MySQL 服务依赖6.1 PyInstaller 打包 tkinter 版强制包含 tcl/tk DLL 与字体文件pyinstaller --onefile main.py生成的 exe 在无 Python 环境的 Windows 上必报错Tcl_AsyncDelete: async handler deleted by the wrong thread。根本原因是 PyInstaller 未打包tcl86t.dll和tk86t.dll# 正确打包命令Windows pyinstaller ^ --onefile ^ --add-binary C:\Python310\tcl\tcl8.6;tcl ^ --add-binary C:\Python310\tcl\tk8.6;tk ^ --add-data C:\Python310\Lib\site-packages\pymysql;PyMySQL ^ --iconapp.ico ^ main.py # Linux/macOS 需额外指定字体路径否则中文显示方块 # 在 main.py 开头添加 import os os.environ[TCL_LIBRARY] /path/to/tcl8.6 os.environ[TK_LIBRARY] /path/to/tk8.6关键参数--add-binary将 tcl/tk 目录作为二进制资源嵌入--add-data确保 PyMySQL 模块被包含--icon指定应用图标.ico格式非.png。6.2 PyQt5 版打包用--exclude-module排除无用 Qt 模块减小体积 40%PyQt5 打包后默认 150MB实际图书馆系统只用QtWidgets和QtSql可排除QtWebEngine、QtBluetooth等pyinstaller ^ --onefile ^ --exclude-module PyQt5.QtWebEngine ^ --exclude-module PyQt5.QtWebEngineCore ^ --exclude-module PyQt5.QtWebChannel ^ --exclude-module PyQt5.QtBluetooth ^ --exclude-module PyQt5.QtPositioning ^ --add-data C:\Python310\Lib\site-packages\PyQt5\Qt\plugins;./plugins ^ --iconapp.ico ^ main.py注意--add-data必须包含plugins目录否则启动报Could not find the Qt platform plugin windows--exclude-module可大幅缩减体积但需确认源码未引用被排除模块。6.3 无 MySQL 服务的终极方案SQLite 替代方案与数据迁移脚本客户环境无法装 MySQL用 SQLite 替代但需处理三类差异MySQL 特性SQLite 等效方案迁移要点AUTO_INCREMENTINTEGER PRIMARY KEYSQLite 的PRIMARY KEY自增无需声明AUTO_INCREMENTDATETIME DEFAULT CURRENT_TIMESTAMPTEXT DEFAULT (datetime(now))SQLite 用datetime(now)且字段类型为TEXTFOREIGN KEYFOREIGN KEY (...) REFERENCES ...SQLite 3.6.19 支持但需PRAGMA foreign_keys ON提供一键迁移脚本mysql_to_sqlite.pyimport sqlite3 import pymysql def migrate_to_sqlite(mysql_config, sqlite_path): # 连接 MySQL mysql_conn pymysql.connect(**mysql_config) cursor mysql_conn.cursor() # 创建 SQLite 连接 sqlite_conn sqlite3.connect(sqlite_path) sqlite_cursor sqlite_conn.cursor() # 启用外键 sqlite_cursor.execute(PRAGMA foreign_keys ON) # 迁移 books 表转换字段类型 sqlite_cursor.execute( CREATE TABLE books ( isbn TEXT PRIMARY KEY, title TEXT NOT NULL, author TEXT DEFAULT , publisher TEXT DEFAULT , publish_year INTEGER DEFAULT NULL, category_id INTEGER DEFAULT NULL, stock INTEGER DEFAULT 1, created_at TEXT DEFAULT (datetime(now)) ) ) # 导出 MySQL 数据并插入 SQLite cursor.execute(SELECT * FROM books) rows cursor.fetchall() sqlite_cursor.executemany( INSERT INTO books VALUES (?, ?, ?, ?, ?, ?, ?, ?), rows ) sqlite_conn.commit() mysql_conn.close() sqlite_conn.close() print(迁移完成) # 使用示例 migrate_to_sqlite( mysql_config{host: 127.0.0.1, user: root, password: pwd, database: library_db}, sqlite_pathlibrary.db )最后一句我坚持在所有交付项目里附带library.db和library.sql两个文件——前者是开箱即用的 SQLite 数据库后者是 MySQL 建表语句客户想换数据库时连读文档的时间都省了。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询