Java超市管理系统与SQL Server实战:从收银到库存的完整实现
简介这份资源是面向Java初学者与课程设计开发者的超市管理系统项目源码基于Java语言结合SQL Server数据库实现适合作为毕业设计、课程作业或企业级入门练手参考。系统覆盖商品管理、库存控制、销售记录、会员管理与报表生成等核心模块技术栈涉及JDBC连接数据库、Servlet与JSP构建MVC架构并引入Spring与MyBatis简化开发与持久层操作数据库层面包含表结构设计、索引优化、存储过程与触发器等实践要点。压缩包为rar格式大小约2.16MB文件总数暂未提供具体文件类型明细暂无数据可参考描述中提及的Java源码与SQL脚本等常见内容。目前已有488人学习下载读者可借此理解Java Web项目与SQL Server整合的完整思路掌握业务模块划分、数据库表设计与性能优化方法为后续独立开发管理系统积累可复用的架构经验与排错参考。1. 从一张收银小票说起Java 超市管理系统配 SQL Server 到底在做什么很多人第一次接触「Java 超市管理系统 SQL Server」这个组合是在课程设计或者小公司内部工具的需求里。它要解决的事情其实很具体把商品、库存、收银、会员、进货这几件事用一套桌面或内网程序管起来数据落在 SQL Server 里。你打开收银台扫一个条码系统要立刻知道这个商品叫什么、卖多少钱、还剩几件结完账库存要减掉小票要打出来。这套东西不追求高并发但要求数据不能乱、金额不能错、断网了也不能把账算丢。适合谁看一是要交课程设计、需要一套能跑起来、能演示、能答辩的系统的人二是小超市、便利店、内部小卖部想自己做个进销存工具的人三是刚学完 JDBC、Swing 或者 Spring Boot想找一个完整业务场景练手的人。它不复杂但坑很集中库存扣减的时机、金额用浮点数、并发下的超卖、SQL Server 的连接配置这几个点几乎每个新手都会翻车一次。下面按「先立住模型再动手复现最后讲坑」的顺序把这条路走一遍。2. 先把数据模型和 SQL Server 环境定下来表结构决定后面好不好改2.1 五张核心表就能撑起一个能演示的系统超市管理系统的表不用一上来就设计几十张先把主链路跑通。常见做法是这五张商品表、库存表、收银订单表、订单明细表、会员表。商品表存条码、名称、进价、售价、分类库存表存商品当前数量和预警值订单表存一笔交易的总额、时间、会员、收银员订单明细存这笔交易里每个商品买了几件、单价多少会员表存卡号、姓名、积分、余额。这里有个关键选择售价到底存在商品表还是订单明细里。血泪经验是两边都要存。商品表里的售价是「当前标价」订单明细里的售价是「成交价」。如果你只存商品表明天老板改价昨天的订单金额跟着变对账直接对不上。订单明细必须把成交那一刻的单价固化下来这是财务类系统的基本纪律。-- 商品表条码做主键避免自增 ID 在扫码场景下还要多查一次 CREATE TABLE Product ( Barcode VARCHAR(32) PRIMARY KEY, ProductName NVARCHAR(64) NOT NULL, Category NVARCHAR(32) NULL, PurchasePrice DECIMAL(10,2) NOT NULL DEFAULT 0, SalePrice DECIMAL(10,2) NOT NULL DEFAULT 0, IsActive BIT NOT NULL DEFAULT 1 ); -- 库存表和商品一对一单独拆表是为了以后加多仓库 CREATE TABLE Inventory ( Barcode VARCHAR(32) PRIMARY KEY, Quantity INT NOT NULL DEFAULT 0, WarnLevel INT NOT NULL DEFAULT 10, UpdatedAt DATETIME NOT NULL DEFAULT GETDATE(), CONSTRAINT FK_Inventory_Product FOREIGN KEY (Barcode) REFERENCES Product(Barcode) );金额字段用DECIMAL(10,2)不要用FLOAT或REAL。浮点数存 0.1 这种值本身就不精确累加几百笔之后总额会飘出几分钱收银对账时这几分钱能让你查一晚上。DECIMAL是定点数SQL Server 里做金额计算是标准做法。2.2 SQL Server 连接配置三个参数不设对程序连不上Java 连 SQL Server 用官方 JDBC 驱动常见的是mssql-jdbc。连接串里最容易出问题的是加密和证书相关的参数。SQL Server 新版本默认要求加密连接本地开发环境如果没有配证书程序会直接报 SSL 错误。// 本地开发用的连接串注意 encrypt 和 trustServerCertificate String url jdbc:sqlserver://localhost:1433; databaseNameSupermarketDB; encrypttrue; trustServerCertificatetrue; loginTimeout10;; String user sa; String password 你的密码;encrypttrue表示启用加密trustServerCertificatetrue表示信任服务端证书、不做严格校验。这两个参数在本地开发时一起用能省掉大量证书配置的麻烦。生产环境应该换成正式证书并把trustServerCertificate关掉。loginTimeout10是登录超时秒数不设的话网络不通时程序会卡很久才报错调试体验很差。还要确认 SQL Server 的 TCP/IP 协议已经启用端口默认 1433。很多人装完默认实例用管理器能连上Java 却连不上八成是 TCP/IP 没开或者防火墙挡了 1433。这两处检查一遍比反复改代码有用。2.3 用连接池还是裸连接小系统也建议上 HikariCP课程设计里常见写法是每次操作DriverManager.getConnection演示没问题但收银界面频繁查询商品时每次建连接的开销会明显拖慢响应。我一般直接上 HikariCP配置也就几行。HikariConfig config new HikariConfig(); config.setJdbcUrl(url); config.setUsername(user); config.setPassword(password); config.setMaximumPoolSize(10); // 小超市并发低10 个连接足够 config.setMinimumIdle(2); // 保持 2 个空闲连接避免频繁创建 config.setConnectionTimeout(5000); // 拿不到连接 5 秒就报错别无限等 HikariDataSource ds new HikariDataSource(config);maximumPoolSize不是越大越好。SQL Server 默认允许的连接数有限小系统设 10 到 20 就够设太大反而会因为连接争抢变慢。connectionTimeout一定要设否则连接池耗尽时线程会一直挂着界面直接假死你还以为是程序卡了。3. 收银主链路怎么写从扫码到扣库存的完整代码3.1 扫码查询商品一次查询把库存一起带出来收银台扫一个条码界面要立刻显示商品名、售价、库存。如果分两次查先查商品再查库存中间会有时间差而且多一次数据库往返。用一条 JOIN 查询更稳。public class ProductDao { private final DataSource ds; public ProductDao(DataSource ds) { this.ds ds; } // 扫码后调用返回商品信息 当前库存 public ProductView findByBarcode(String barcode) throws SQLException { String sql SELECT p.Barcode, p.ProductName, p.SalePrice, i.Quantity FROM Product p JOIN Inventory i ON i.Barcode p.Barcode WHERE p.Barcode ? AND p.IsActive 1; try (Connection conn ds.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, barcode); try (ResultSet rs ps.executeQuery()) { if (!rs.next()) return null; // 商品不存在或已下架 ProductView v new ProductView(); v.barcode rs.getString(Barcode); v.name rs.getString(ProductName); v.price rs.getBigDecimal(SalePrice); v.stock rs.getInt(Quantity); return v; } } } }用PreparedStatement而不是拼字符串一是防注入二是 SQL Server 能缓存执行计划重复扫码时更快。IsActive 1这个条件别漏下架商品还能扫出来卖是常见事故。返回null表示查不到界面要给出明确提示而不是显示一个空白行。3.2 结账扣库存事务和行锁是防超卖的关键一笔交易要同时做几件事写订单主表、写订单明细、扣库存、加会员积分。这几步必须在一个事务里要么全成功要么全回滚。更关键的是扣库存时要防止并发超卖——两个收银台同时卖最后一件商品如果都先查再扣就会扣成负数。public void checkout(Order order) throws SQLException { String insertOrder INSERT INTO SalesOrder(OrderNo, MemberId, TotalAmount, Cashier, CreatedAt) VALUES(?,?,?,?,GETDATE()); String insertItem INSERT INTO OrderItem(OrderNo, Barcode, Quantity, UnitPrice) VALUES(?,?,?,?); // 关键扣库存时带条件库存不足则影响行数为 0 String deductStock UPDATE Inventory SET Quantity Quantity - ?, UpdatedAt GETDATE() WHERE Barcode ? AND Quantity ?; try (Connection conn ds.getConnection()) { conn.setAutoCommit(false); // 开启事务 try (PreparedStatement psOrder conn.prepareStatement(insertOrder); PreparedStatement psItem conn.prepareStatement(insertItem); PreparedStatement psStock conn.prepareStatement(deductStock)) { psOrder.setString(1, order.orderNo); psOrder.setString(2, order.memberId); psOrder.setBigDecimal(3, order.totalAmount); psOrder.setString(4, order.cashier); psOrder.executeUpdate(); for (OrderItem item : order.items) { psItem.setString(1, order.orderNo); psItem.setString(2, item.barcode); psItem.setInt(3, item.quantity); psItem.setBigDecimal(4, item.unitPrice); psItem.executeUpdate(); psStock.setInt(1, item.quantity); psStock.setString(2, item.barcode); psStock.setInt(3, item.quantity); int affected psStock.executeUpdate(); if (affected 0) { // 库存不足抛异常触发回滚 throw new SQLException(库存不足: item.barcode); } } conn.commit(); } catch (SQLException e) { conn.rollback(); // 任何一步失败整笔交易回滚 throw e; } } }UPDATE ... WHERE Quantity ?这个写法是防超卖的核心。数据库在执行 UPDATE 时会对目标行加锁判断和扣减在一条语句里原子完成。如果库存不够affected就是 0直接抛异常回滚。这比「先 SELECT 查库存再判断再 UPDATE」可靠得多后者在并发下必然出问题。setAutoCommit(false)之后一定要在 catch 里rollback否则连接归还到池里时事务状态是脏的下一个用这个连接的操作会莫名其妙失败。这是连接池使用中最隐蔽的坑之一。3.3 订单号生成别用时间戳会撞订单号常见做法是「日期 流水号」。直接用System.currentTimeMillis()在并发下会重复尤其是同一秒内两笔交易。稳妥做法是用数据库序列或者一张专门的流水号表在事务里自增。-- 用 SQL Server 的 SEQUENCE 生成每日流水 CREATE SEQUENCE Seq_OrderNo AS BIGINT START WITH 1 INCREMENT BY 1; -- 取号时拼上日期 SELECT CONVERT(VARCHAR(8), GETDATE(), 112) RIGHT(000000 CAST(NEXT VALUE FOR Seq_OrderNo AS VARCHAR(6)), 6) AS OrderNo;CONVERT(..., 112)得到yyyyMMdd格式RIGHT(000000 ..., 6)补足六位。这样订单号既有序又不会撞。如果不想用 SEQUENCE用一张OrderNoSeq表加行锁自增也行原理一样把取号动作放进事务靠数据库保证唯一。4. 避坑与排查这五个问题几乎每个项目都会遇到4.1 中文商品名存进去变问号现象插入「可口可乐」这种中文数据库里显示成??或者乱码。原因通常是字段类型用了VARCHAR而不是NVARCHAR或者 JDBC 连接串没指定字符集。解决所有存中文的字段用NVARCHAR连接串加sendStringParametersAsUnicodetrue部分驱动版本需要并且确认数据库排序规则支持中文。改字段类型时注意VARCHAR转NVARCHAR要重建或 ALTER已有数据可能已经损坏需要重新导入。4.2 金额算出来差几分钱现象订单总额和明细逐条相加对不上差 0.01 到 0.05。原因是用double做金额运算或者数据库字段用了FLOAT。解决Java 侧统一用BigDecimal数据库侧统一用DECIMAL(10,2)。BigDecimal做除法时要指定精度和舍入模式比如divide(new BigDecimal(3), 2, RoundingMode.HALF_UP)不指定会抛ArithmeticException。4.3 程序启动报「连接被拒绝」现象The TCP/IP connection to the host localhost, port 1433 has failed。原因按概率排SQL Server 的 TCP/IP 协议没启用端口不是 1433防火墙拦截实例名写错。解决打开 SQL Server 配置管理器确认 TCP/IP 状态是「已启用」查看 IP 地址页签里的 TCP 端口在服务里确认 SQL Server 服务在运行用telnet localhost 1433测端口通不通。这四步走完九成连接问题能定位。4.4 库存扣成负数现象某个商品库存显示 -3。原因是没有用带条件的 UPDATE或者扣减逻辑写在了事务外面。解决扣库存必须用UPDATE ... WHERE Quantity ?并检查影响行数且整个结账流程在一个事务里。已经出现的负数要人工盘点修正同时加一条数据库约束CHECK (Quantity 0)兜底让错误在写入时就暴露而不是等到盘点才发现。4.5 界面卡死点结账没反应现象点结账按钮后界面无响应过很久才恢复或直接假死。原因是在 Swing 的事件线程EDT里直接做了数据库操作网络慢或锁等待时整个界面就冻住。解决把数据库操作放到后台线程用SwingWorker或者线程池执行完成后回 EDT 更新界面。这是桌面程序最常见的性能问题跟数据库本身没关系但表现得很像数据库慢。5. 进阶技巧把对账和库存预警做成可验证的日常动作系统能收银只是及格线真正让它有价值的是「每天能对账、库存低了能提醒」。我一般会加两个动作。第一个是日结查询每天营业结束跑一次把当天订单总额、明细汇总、现金/会员支付分开统计和收银员手里的现金对一遍。这个查询本身不复杂但它是发现数据问题的第一道防线。-- 日结按支付方式汇总当天交易 SELECT PaymentType, COUNT(*) AS OrderCount, SUM(TotalAmount) AS TotalAmount FROM SalesOrder WHERE CAST(CreatedAt AS DATE) CAST(GETDATE() AS DATE) GROUP BY PaymentType;CAST(CreatedAt AS DATE)把时间截断到天比用BETWEEN拼时间字符串更不容易出错。如果数据量大CreatedAt上要建索引否则每天全表扫会越来越慢。第二个是库存预警用一条查询把低于预警值的商品列出来收银界面开一个角标或者每天早上自动弹一次。SELECT p.Barcode, p.ProductName, i.Quantity, i.WarnLevel FROM Inventory i JOIN Product p ON p.Barcode i.Barcode WHERE i.Quantity i.WarnLevel AND p.IsActive 1 ORDER BY i.Quantity ASC;Quantity WarnLevel这个条件让预警值可配置不同商品可以设不同的阈值比写死一个数字灵活。这两个查询建议做成独立的 DAO 方法不要塞进收银流程里避免互相影响。验证系统是否可靠我有个习惯每次改完扣库存或金额相关的代码手动造三组数据跑一遍——正常结账、库存刚好等于购买量、库存不足。三组都过了再提交。这个习惯帮我拦下过好几次「看起来没问题、一并发就出错」的改动。系统不大但账目类的东西宁可多测一遍也别等老板拿着小票来找你。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

SVM短期负荷预测实战:从例程到避坑指南

SVM短期负荷预测实战:从例程到避坑指南

简介:这份例程面向电力系统负荷预测方向的学习者与研究人员,聚焦支持向量机在短期负荷预测中的落地应用。与直接将影响因素送入模型的常规做法不同,它在训练前对各影响因素进行加权预处理,以突出关键特征、削弱弱相关因素干扰&…

2026/10/13 12:30:31 阅读更多 →
WebAssembly沙箱逃逸攻防:边界、漏洞与安全加固实践

WebAssembly沙箱逃逸攻防:边界、漏洞与安全加固实践

1. 先搞清楚一件事:WebAssembly沙箱到底在拦谁 提到WebAssembly沙箱,大多数人第一反应是“安全、隔离、可控”,甚至有些人直接把它当成“轻量级容器”来用。但干了几年安全攻防之后,我对这类说法的态度越来越谨慎:沙箱…

2026/10/13 12:30:31 阅读更多 →
View UI表格拖拽排序实战:Sortable.js正确绑定tbody

View UI表格拖拽排序实战:Sortable.js正确绑定tbody

1. 先搞清楚 View UI 表格拖拽排序的几个关键前提给 iView(现在叫 View UI)的表格加拖拽排序,是我这几年在后台管理系统里做过不下三次的需求。第一次我直接修改 data 数组的顺序,结果表格纹丝不动;第二次我把 Sortabl…

2026/10/13 12:30:31 阅读更多 →

最新新闻

RabbitMQ从0到1:核心模型、生产实践与高频问题排查指南

RabbitMQ从0到1:核心模型、生产实践与高频问题排查指南

如果你手头有个项目需要在系统里传递消息,十有八九会想到RabbitMQ。但很多人装完、跑个Hello World就算“会用”了,等遇到连接失败、消息丢失、谁该消费谁不该消费、甚至admin账号没法创建virtual host时,才发现自己其实并不理解它。这篇就从…

2026/10/13 13:13:23 阅读更多 →
CANN全面开源:异构计算架构如何让性能调优不再靠猜

CANN全面开源:异构计算架构如何让性能调优不再靠猜

1. 先搞清楚CANN是什么,以及“开源开放”为什么是一条难走但必须走的路 很多做AI开发的同行,第一次听到CANN这个缩写,是在跑模型的时候拿到一张报错截图,或者是在某个加速卡的性能优化文档里。CANN的全称是异构计算架构&#xff0…

2026/10/13 13:13:23 阅读更多 →
Python+微信小程序+AI:从零搭建对话式健康风险评估系统

Python+微信小程序+AI:从零搭建对话式健康风险评估系统

最近半年我一直泡在一个“Python 微信小程序 AI健康问诊”的个人项目里。起因很简单:家里人经常在小程序里看各种健康问答,但问题描述得零零散散,得到的回答又是通用模板,根本没结合个人的基础情况。我就想,能不能自…

2026/10/13 13:13:23 阅读更多 →
若依集成EasyExcel实战:告别手写POI,搞定复杂表头与大数据导出

若依集成EasyExcel实战:告别手写POI,搞定复杂表头与大数据导出

从写下第一行导出代码到最后彻底放弃手写 POI,大概花了我整整两周时间。彼时我们的若依后台管理系统刚好需要一批新的报表导出功能,领导给了个听起来特别简单的要求:把数据导成 Excel,表头要好看点,列宽自动适应&#…

2026/10/13 13:13:23 阅读更多 →
AI产品经理的五种分化:从模型微调到行业落地,你适合哪一类?

AI产品经理的五种分化:从模型微调到行业落地,你适合哪一类?

最近好几个朋友来找我聊转行,说想往AI产品经理方向走,结果翻了一圈招聘JD直接懵了:同一个岗位名称,有的要求懂Transformer、懂模型微调,有的只要会画原型写PRD,有的甚至要跟着销售跑客户。这到底是一个岗位…

2026/10/13 13:13:23 阅读更多 →
Mars版Eclipse绿色版配置指南:JAVA_HOME、Tomcat与避坑要点

Mars版Eclipse绿色版配置指南:JAVA_HOME、Tomcat与避坑要点

简介:这是一份Eclipse JEE Mars R的Windows 64位官方绿色版压缩包,面向Java企业级与Web开发者,针对J2EE项目开发与调试环境而封装。版本基于2015年6月30日发布的Mars R正式版,解压后免安装即可运行,省去安装向导与手动…

2026/10/13 13:12:22 阅读更多 →

日新闻

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

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

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

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/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

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

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

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

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

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

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

月新闻

我发现了一个新思路:用 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 阅读更多 →