资讯动态

Java超市管理系统与SQL Server实战:从收银到库存的完整实现

发布时间:2026/10/13 12:31:34 来源:尧图企业网站定制
简介这份资源是面向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 方法不要塞进收银流程里避免互相影响。验证系统是否可靠我有个习惯每次改完扣库存或金额相关的代码手动造三组数据跑一遍——正常结账、库存刚好等于购买量、库存不足。三组都过了再提交。这个习惯帮我拦下过好几次「看起来没问题、一并发就出错」的改动。系统不大但账目类的东西宁可多测一遍也别等老板拿着小票来找你。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑