☰
SpringBoot仓库管理系统设计与并发控制实践
2026/10/14 9:50:49 网站建设 项目流程

1. 项目背景与核心价值

这个基于SpringBoot的仓库管理系统是我去年指导的一个计算机专业本科毕业设计项目。当时学生找到我,说想做一个"能实际用起来"的仓库管理工具,而不是常见的玩具级DEMO。经过两周的需求梳理和技术选型,我们最终确定了这个方案。

系统最大的特点是业务闭环完整。从采购入库、库存调拨到出库盘点,覆盖了中小型企业仓储管理的全流程。特别设计了批次管理和效期预警功能,这对食品、医药等行业的同学特别实用。整个项目采用SpringBoot+MyBatis经典架构,前端用Thymeleaf模板引擎,数据库支持MySQL和Oracle双版本。

提示:源码中的55711是项目版本号,对应2023年5月发布的稳定版,修复了初期版本中的库存并发问题。

2. 技术架构解析

2.1 后端技术栈设计

采用SpringBoot 2.7.4作为基础框架,主要考虑因素包括:

  • 内嵌Tomcat简化部署
  • 自动配置减少XML配置
  • 丰富的Starter依赖

核心依赖项说明:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency>

2.2 数据库设计要点

库存管理最关键的三个表结构设计:

  1. 商品主表(product)
CREATE TABLE `product` ( `id` int NOT NULL AUTO_INCREMENT, `code` varchar(32) NOT NULL COMMENT '商品编码', `name` varchar(100) NOT NULL, `spec` varchar(50) DEFAULT NULL COMMENT '规格', `unit` varchar(10) DEFAULT '个' COMMENT '单位', `category_id` int DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  1. 库存表(stock)
CREATE TABLE `stock` ( `id` int NOT NULL AUTO_INCREMENT, `product_id` int NOT NULL, `warehouse_id` int NOT NULL, `batch_no` varchar(50) DEFAULT NULL COMMENT '批次号', `quantity` decimal(12,3) NOT NULL DEFAULT '0', `lock_quantity` decimal(12,3) DEFAULT '0' COMMENT '锁定数量', `product_date` date DEFAULT NULL COMMENT '生产日期', `expire_date` date DEFAULT NULL COMMENT '过期日期', PRIMARY KEY (`id`), UNIQUE KEY `uk_product_warehouse` (`product_id`,`warehouse_id`,`batch_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  1. 库存流水表(stock_flow)
CREATE TABLE `stock_flow` ( `id` bigint NOT NULL AUTO_INCREMENT, `flow_no` varchar(32) NOT NULL COMMENT '流水号', `product_id` int NOT NULL, `before_quantity` decimal(12,3) DEFAULT NULL, `change_quantity` decimal(12,3) NOT NULL, `after_quantity` decimal(12,3) DEFAULT NULL, `operator` varchar(50) DEFAULT NULL, `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_product` (`product_id`), KEY `idx_flow_no` (`flow_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. 核心功能实现

3.1 库存扣减的并发控制

这是系统最核心的技术难点。我们采用乐观锁+数据库事务的方案:

@Transactional public boolean deductStock(Long productId, Long warehouseId, String batchNo, BigDecimal quantity) { // 1. 查询当前库存 Stock stock = stockMapper.selectForUpdate(productId, warehouseId, batchNo); // 2. 校验库存是否充足 if(stock.getAvailableQuantity().compareTo(quantity) < 0){ throw new BusinessException("库存不足"); } // 3. 扣减库存 int rows = stockMapper.deductQuantity(stock.getId(), quantity); if(rows == 0){ throw new ConcurrentUpdateException("库存并发修改冲突"); } // 4. 记录流水 StockFlow flow = new StockFlow(); flow.setFlowNo(generateFlowNo()); flow.setProductId(productId); // ...其他字段设置 flowMapper.insert(flow); return true; }

注意:selectForUpdate方法要加@Lock(LockModeType.PESSIMISTIC_WRITE)注解,这是防止超卖的关键。

3.2 效期预警实现方案

通过Spring Scheduled实现每日凌晨检查:

@Scheduled(cron = "0 0 3 * * ?") public void checkExpireWarning() { LocalDate warnDate = LocalDate.now().plusDays(expireWarningDays); List<Stock> warningStocks = stockMapper.selectExpireWarning(warnDate); if(!warningStocks.isEmpty()){ // 发送邮件通知 emailService.sendExpireWarning(warningStocks); // 生成预警记录 warningStocks.forEach(stock -> { ExpireWarning warning = new ExpireWarning(); warning.setStockId(stock.getId()); // ...其他字段设置 expireWarningMapper.insert(warning); }); } }

4. 系统部署与调优

4.1 生产环境配置建议

application-prod.yml关键配置:

spring: datasource: url: jdbc:mysql://127.0.0.1:3306/warehouse?useSSL=false&serverTimezone=Asia/Shanghai username: warehouse password: ${DB_PASSWORD} hikari: maximum-pool-size: 20 connection-timeout: 30000 mybatis: configuration: default-fetch-size: 100 map-underscore-to-camel-case: true

4.2 性能优化实践

  1. 缓存策略:
  • 商品基础信息用Redis缓存
  • 使用Spring Cache抽象层
@Cacheable(value = "product", key = "#productId") public Product getProductById(Long productId) { return productMapper.selectById(productId); }
  1. 批量操作优化:
public void batchImport(List<Product> products) { // 使用MyBatis批量插入 SqlSession session = sqlSessionTemplate.getSqlSessionFactory() .openSession(ExecutorType.BATCH); try { ProductMapper mapper = session.getMapper(ProductMapper.class); for (Product product : products) { mapper.insert(product); } session.commit(); } finally { session.close(); } }

5. 常见问题解决方案

5.1 库存不一致排查

遇到库存数据异常时,按以下步骤排查:

  1. 检查stock_flow流水记录
SELECT * FROM stock_flow WHERE product_id = ? ORDER BY create_time DESC LIMIT 10;
  1. 比对最后一条流水的after_quantity与当前库存

  2. 如果没有流水记录但库存变化,检查是否有直接SQL更新

5.2 效期预警不生效

检查清单:

  1. 确认spring.task.scheduling.enabled=true
  2. 检查数据库时区设置
  3. 查看应用日志是否有定时任务执行记录
  4. 手动执行方法测试:
@Test public void testExpireCheck() { expireService.checkExpireWarning(); }

6. 项目扩展建议

  1. 多仓库调拨功能:
public void transferStock(TransferForm form) { // 1. 扣减源仓库库存 deductStock(form.getFromProductId(), form.getFromWarehouseId(), form.getBatchNo(), form.getQuantity()); // 2. 增加目标仓库库存 addStock(form.getToProductId(), form.getToWarehouseId(), form.getBatchNo(), form.getQuantity()); // 3. 记录调拨单 transferMapper.insert(form); }
  1. 报表分析模块:
  • 使用EasyExcel导出库存报表
  • 集成ECharts实现数据可视化
  1. 移动端适配:
  • 增加H5页面
  • 使用Vue.js重构前端

这个项目经过三个月的迭代已经相对完善,特别适合需要实际业务场景练手的同学。源码中的55711版本特别加强了事务处理和异常监控,建议在此基础上进行二次开发。我在实际部署时发现,对于日均流水5000条以上的场景,需要增加Redis缓存和异步日志处理,这部分可以作为进阶优化方向。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询