Python库存管理系统课程设计:源码+SQL+报告全流程避坑指南
简介这是一套面向高校学生与Python初学者、用于课程设计或数据库大作业的库存管理系统完整资料包含源码、SQL文件与设计报告三部分可帮助读者理解从需求分析到功能落地的完整开发流程。压缩包共1473个文件约28.52MB以ts、html、js、scss、less等前端资源为主辅以py、pyc等Python源码与编译文件另有sql、sqlite3数据库文件及md、pdf、docx等说明文档目录结构清晰便于按模块查阅。系统覆盖商品信息管理、库存信息管理、入库出库操作、库存查询统计与用户权限管理等核心模块设计报告则对数据库表结构、字段约束与表间关系作了详细阐述。目前已有44人学习下载适合需要参考完整项目结构、数据库设计思路与Python业务实现细节的读者借鉴使用。1. 从一份课程设计说起Python 库存管理系统到底要交付什么每年到了期末总有一批人卡在“库存管理系统”这个选题上。标题里写着“源码sql文件设计报告”看起来三样东西齐了就能交差但真正动手才发现源码跑不起来、sql 文件导入报错、设计报告和代码对不上号。我带过几届学生的课程设计也帮朋友改过类似的单子最常见的翻车现场不是代码写得多烂而是环境没配对、数据库没连上、表结构跟代码里的字段名差一个字母。这个方案适合谁一是正在做课程设计、需要一套能跑通的 Python 库存管理系统的人二是想拿它当练手项目、把增删改查和数据库操作串一遍的入门者。它解决的核心问题很具体用 Python 把商品入库、出库、库存查询、低库存预警这几个动作跑通数据落到 MySQL 里最后能生成一份说得清设计思路的报告。下面我按实际落地的顺序把环境、表结构、核心代码、避坑点拆开讲。2. 环境与依赖把 Python 和 MySQL 先接上2.1 为什么选 PyMySQL 而不是 MySQLdbPython 连 MySQL 的库有好几个常见的是 MySQLdb、PyMySQL、mysql-connector-python。MySQLdb 在 Windows 上装起来经常卡在编译环节mysql-connector 是官方出品但 API 风格跟课程设计里常见的写法不太一样。PyMySQL 是纯 Python 实现pip 一条命令就能装代码里import pymysql直接能用对新手最友好。我一般会先确认 Python 版本3.8 到 3.11 都行再装依赖。# 确认 Python 版本建议 3.8 以上 python --version # 安装 PyMySQL这是连 MySQL 的核心库 pip install pymysql # 如果要做界面装 tkinter 相关标准库自带一般不用额外装 # 如果要用到日期处理装 datetime标准库自带装完之后别急着写代码先确认 MySQL 服务是活的。Windows 下在服务里看 MySQL 是否运行Linux 下用systemctl status mysql。这一步跳过的人后面报Cant connect to MySQL server的时候会找半天。2.2 建库建表的 sql 文件怎么导入标题里的“sql 文件”通常包含建库、建表、插初始数据三部分。我习惯把库名定为inventory_db字符集用utf8mb4不然商品名里的中文会变问号。导入方式有两种命令行和图形工具。命令行更稳不容易因为工具版本差异出问题。# 登录 MySQL输入密码 mysql -u root -p # 在 MySQL 命令行里执行 sql 文件 source /path/to/inventory.sql; # 或者退出后用命令行直接导入 mysql -u root -p inventory_db /path/to/inventory.sql导入之后一定要验证use inventory_db; show tables;看表在不在select * from product limit 5;看数据有没有进去。我见过有人导入时没指定库结果表建到了别的库里代码连上去查不到表报Table inventory_db.product doesnt exist。2.3 数据库连接配置的写法与参数说明连接配置我一般单独放一个db_config.py不硬编码在主程序里。这样换环境只改一个文件。关键参数有五个host、port、user、password、database再加一个 charset。# db_config.py import pymysql def get_connection(): return pymysql.connect( hostlocalhost, # 数据库地址本机就是 localhost port3306, # MySQL 默认端口改过就填改后的 userroot, # 用户名 passwordyour_pass, # 换成你自己的密码 databaseinventory_db, # 库名要和 sql 文件里一致 charsetutf8mb4, # 字符集防止中文乱码 cursorclasspymysql.cursors.DictCursor # 让查询结果以字典返回 )cursorclass设成DictCursor之后fetchone()返回的是{product_name: 螺丝刀, stock: 20}这种形式取值用row[product_name]比用下标row[1]可读性好得多。密码不要写死成123456然后提交到公开仓库这是血泪经验改起来一分钟泄露了很麻烦。3. 核心功能落地入库、出库、查询、预警怎么写3.1 商品表的字段设计与 sql 建表语句表结构设计不好后面代码怎么写都别扭。商品表我一般叫product字段包括自增主键id、商品编号product_code唯一、商品名product_name、规格spec、库存数量stock、库存下限min_stock、创建时间create_time。库存下限是用来做预警的低于这个值就提示补货。CREATE TABLE product ( id INT NOT NULL AUTO_INCREMENT, product_code VARCHAR(50) NOT NULL UNIQUE COMMENT 商品编号, product_name VARCHAR(100) NOT NULL COMMENT 商品名称, spec VARCHAR(100) DEFAULT NULL COMMENT 规格, stock INT NOT NULL DEFAULT 0 COMMENT 当前库存, min_stock INT NOT NULL DEFAULT 10 COMMENT 库存下限, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;product_code加 UNIQUE 约束防止重复录入同一个商品。stock和min_stock用 INT别用 VARCHAR不然排序和比较会出玄学问题。create_time默认当前时间插入时不用手动传。3.2 入库操作的完整函数与事务处理入库不是简单地把 stock 加一下。正确做法是先查商品是否存在存在就更新库存不存在就插入新商品整个过程放在一个事务里。这样中途出错可以回滚不会出现“库存加了但日志没记”的情况。import pymysql from db_config import get_connection def stock_in(product_code, product_name, spec, quantity, min_stock10): 入库操作商品存在则增加库存不存在则新建 quantity: 入库数量必须为正整数 if quantity 0: return False, 入库数量必须大于 0 conn get_connection() try: with conn.cursor() as cursor: # 先查商品是否存在 sql_check SELECT id, stock FROM product WHERE product_code %s cursor.execute(sql_check, (product_code,)) result cursor.fetchone() if result: # 存在更新库存 new_stock result[stock] quantity sql_update UPDATE product SET stock %s WHERE product_code %s cursor.execute(sql_update, (new_stock, product_code)) else: # 不存在插入新记录 sql_insert INSERT INTO product (product_code, product_name, spec, stock, min_stock) VALUES (%s, %s, %s, %s, %s) cursor.execute(sql_insert, (product_code, product_name, spec, quantity, min_stock)) # 记录入库日志假设有 log 表 sql_log INSERT INTO stock_log (product_code, change_type, change_qty) VALUES (%s, IN, %s) cursor.execute(sql_log, (product_code, quantity)) conn.commit() return True, 入库成功 except Exception as e: conn.rollback() return False, f入库失败{str(e)} finally: conn.close()with conn.cursor()这种写法会自动关闭游标不用手动cursor.close()。conn.commit()放在with外面确保所有操作都成功才提交。except里先rollback()再返回错误信息这样数据不会脏。参数用%s占位不要用字符串拼接否则商品名里带单引号就会 SQL 报错这也是常见的注入隐患。3.3 出库与库存不足的判断逻辑出库比入库多一层判断库存够不够。不够就直接拒绝不要先减再补。判断和更新要在同一个事务里避免并发时超卖。def stock_out(product_code, quantity): 出库操作先判断库存是否充足充足则扣减 if quantity 0: return False, 出库数量必须大于 0 conn get_connection() try: with conn.cursor() as cursor: # 加 FOR UPDATE 锁住这一行防止并发扣减 sql_check SELECT stock FROM product WHERE product_code %s FOR UPDATE cursor.execute(sql_check, (product_code,)) result cursor.fetchone() if not result: return False, 商品不存在 if result[stock] quantity: return False, f库存不足当前库存 {result[stock]} sql_update UPDATE product SET stock stock - %s WHERE product_code %s cursor.execute(sql_update, (quantity, product_code)) sql_log INSERT INTO stock_log (product_code, change_type, change_qty) VALUES (%s, OUT, %s) cursor.execute(sql_log, (product_code, quantity)) conn.commit() return True, 出库成功 except Exception as e: conn.rollback() return False, f出库失败{str(e)} finally: conn.close()FOR UPDATE是行级锁在事务里锁住查询到的行别的事务要改这一行就得等。课程设计里并发场景不多但写上这个能体现你考虑过数据一致性。注意FOR UPDATE必须在事务里用autocommit 模式下不生效。3.4 库存查询与低库存预警的 sql 写法查询分两种按商品编号精确查和查全部。预警就是查stock min_stock的记录。sql 本身不复杂关键是返回结果的处理。def query_stock(product_codeNone): 查询库存传编号查单个不传查全部 conn get_connection() try: with conn.cursor() as cursor: if product_code: sql SELECT * FROM product WHERE product_code %s cursor.execute(sql, (product_code,)) return cursor.fetchone() else: sql SELECT * FROM product ORDER BY stock ASC cursor.execute(sql) return cursor.fetchall() finally: conn.close() def low_stock_alert(): 返回所有低于库存下限的商品 conn get_connection() try: with conn.cursor() as cursor: sql SELECT * FROM product WHERE stock min_stock cursor.execute(sql) return cursor.fetchall() finally: conn.close()ORDER BY stock ASC让库存少的排前面一眼能看到哪些快没了。预警查询用而不是因为等于下限时通常还算安全低于才需要补。这个细节设计报告里可以写一句显得有思考。4. 避坑与排查那些让系统跑不起来的常见问题4.1 中文乱码从建库到连接的三处字符集现象商品名存进去变成???或者乱码。原因通常有三处建库时没指定字符集、建表时没指定、连接时没指定。解决方法是三处都统一成utf8mb4。建库语句写成CREATE DATABASE inventory_db DEFAULT CHARSET utf8mb4;建表末尾加DEFAULT CHARSETutf8mb4连接参数里加charsetutf8mb4。三处缺一处都可能出问题我一般建完库先show variables like character%;确认一下。4.2 导入 sql 文件报 1064 或 1046现象source导入时提示语法错误或者“No database selected”。原因一是 sql 文件里没有USE inventory_db;二是文件编码不是 UTF-8。解决方法是打开 sql 文件在开头手动加一行USE inventory_db;并确认文件保存为 UTF-8 无 BOM 格式。Windows 记事本默认可能带 BOM用 VS Code 或 Notepad 转一下。4.3 连接报 2003MySQL 服务没起或端口不对现象pymysql.err.OperationalError: (2003, Cant connect to MySQL server on localhost)。原因一是 MySQL 服务没启动二是端口不是 3306三是防火墙拦了。解决方法是先net start mysqlWindows或systemctl start mysqlLinux再确认端口show variables like port;能看到实际端口。如果改过端口连接配置里也要改。4.4 出库后库存变负数现象明明判断了库存不足还是出现了负数。原因通常是判断和更新之间没有锁两个请求同时读到相同库存都判断通过然后都扣减。解决方法是像 3.3 那样用FOR UPDATE锁行或者把判断和更新合并成一条 sqlUPDATE product SET stock stock - %s WHERE product_code %s AND stock %s看影响行数是否为 1。后者更简洁推荐。4.5 设计报告和代码对不上现象报告里写的表字段和代码里用的不一致或者报告里的功能代码里没实现。原因是先写报告后写代码或者改代码没同步改报告。解决方法是先定表结构代码按表结构写报告里的 ER 图和字段说明直接从DESC product;的输出复制。改代码时顺手在报告里标一下别等最后对不上再返工。5. 进阶技巧把系统从“能跑”推到“好用”5.1 用上下文管理器简化数据库操作每次写try...finally关连接太啰嗦。可以写一个上下文管理器把连接和关闭包起来。from contextlib import contextmanager contextmanager def db_cursor(): conn get_connection() try: with conn.cursor() as cursor: yield cursor conn.commit() except Exception: conn.rollback() raise finally: conn.close() # 用的时候 with db_cursor() as cursor: cursor.execute(SELECT * FROM product) rows cursor.fetchall()这样业务代码里不用重复写 commit 和 close出错自动回滚。yield之前是进入时的操作之后是退出时的操作。注意conn.commit()放在with conn.cursor()外面确保游标关闭后再提交。5.2 给查询加分页避免数据多了卡死商品上千条之后fetchall()一次全取出来会占内存界面也会卡。加 LIMIT 和 OFFSET 分页。def query_stock_page(page1, page_size20): offset (page - 1) * page_size conn get_connection() try: with conn.cursor() as cursor: sql SELECT * FROM product ORDER BY id LIMIT %s OFFSET %s cursor.execute(sql, (page_size, offset)) return cursor.fetchall() finally: conn.close()page从 1 开始offset是跳过的行数。page_size一般 20 到 50看界面能显示多少行。别忘了再写一个count查询算总页数不然不知道有多少页。5.3 用日志表追溯每一次库存变动只改product表的 stock出了问题查不到是谁改的、什么时候改的。加一张stock_log表每次入库出库都插一条。CREATE TABLE stock_log ( id INT NOT NULL AUTO_INCREMENT, product_code VARCHAR(50) NOT NULL, change_type ENUM(IN,OUT) NOT NULL, change_qty INT NOT NULL, change_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;change_type用 ENUM 限制只能填 IN 或 OUT防止写错。查某个商品的所有变动SELECT * FROM stock_log WHERE product_code P001 ORDER BY change_time DESC;。这个表在写设计报告时也是加分项说明你考虑了审计和追溯。5.4 验证系统是否真的跑通三个必做测试写完代码别急着交跑三个测试。第一入库一个新商品查库存是否为入库数量。第二出库数量大于库存看是否返回“库存不足”且库存没变。第三把某个商品库存改到低于下限调预警函数看是否返回该商品。三个都过了基本功能就没问题。我习惯把测试结果截图放进设计报告比空口说“已实现”有说服力。最后说个习惯每次改完代码先把db_config.py里的密码换成自己的再跑别用别人的配置。数据库连接失败时先看服务起没起再看端口和密码最后看库名和表名。这个顺序能省很多时间。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

AnyPS5:跨平台游戏串流方案的设计与实现

AnyPS5:跨平台游戏串流方案的设计与实现

1. 从“AnyPS5”这个标题说起:一个跨平台游戏串流方案的设计与实现第一次看到“AnyPS5”这个标题,我的直觉是:这应该是一个让PS5游戏画面能在任意设备上显示和操作的项目。说白了,就是把PS5的画面串流到手机、平板、笔记本甚至电视…

2026/10/13 0:21:51 阅读更多 →
Spring单例Bean线程安全问题:原理、排查与五大解决实践

Spring单例Bean线程安全问题:原理、排查与五大解决实践

做了这么多年Java后端,每次线上出了诡异问题,排查到最后一层,十有八九都绕不开Spring单例线程安全。这个点既是面试必考题,也是生产环境最常见的坑之一。Spring默认把Bean设计成单例,而单例意味着全局共享,…

2026/10/13 0:21:51 阅读更多 →
Java集合框架核心:从Collection接口到List与Set实现原理与选型

Java集合框架核心:从Collection接口到List与Set实现原理与选型

1. 集合框架的起点:为什么必须先搞懂Collection接口很多同学刚开始学Java集合时,容易一头扎进ArrayList、HashMap的源码里,背了一堆方法名和底层结构,真到写代码的时候却不知道该选哪个。这个问题我见过太多次了,归根结…

2026/10/13 0:21:51 阅读更多 →

最新新闻

CentOS 7.x下用Docker与Shell脚本一键部署Redis Cluster集群

CentOS 7.x下用Docker与Shell脚本一键部署Redis Cluster集群

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:51 阅读更多 →
AI芯片软硬件协同优化实战:寄存器可配置化设计方法

AI芯片软硬件协同优化实战:寄存器可配置化设计方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:51 阅读更多 →
C#虚属性与抽象属性重写详解:以Label控件为例

C#虚属性与抽象属性重写详解:以Label控件为例

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:51 阅读更多 →
NFine框架登录流程源码深度解析:从MVC分层到权限体系实战

NFine框架登录流程源码深度解析:从MVC分层到权限体系实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:51 阅读更多 →
STM32 Systick滴答定时器:从原理到实战的精准延时方案

STM32 Systick滴答定时器:从原理到实战的精准延时方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:09:51 阅读更多 →
基于开路电压的改进型MPPT算法:快速辐照变化下光伏逆变器的可靠跟踪方案

基于开路电压的改进型MPPT算法:快速辐照变化下光伏逆变器的可靠跟踪方案

快速变天时,光伏逆变器最怕的不是功率不够,而是明明太阳明晃晃地照着,MPPT却在“原地打转”——电压来回扫,功率丢掉一大截。我这些年调试组串式逆变器,遇到最多的就是这种快速变化辐照下的MPPT失效问题,尤…

2026/10/13 1:08:51 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →