WMS仓储系统(五)—— 入库流程面试题精讲(项目实战篇)
WMS仓储系统(五)—— 入库流程面试题精讲(项目实战篇)
接上一篇:WMS仓储系统(四)—— 库存模块面试题与项目亮点(面试必看) :我们系统总结了库存模块的简历亮点与高频面试题。本文基于项目真实源码,深入拆解入库流程的完整实现,包含到货通知、质检、待上架、上架、库存更新、事务控制等核心环节,并整理15道高频面试题与标准答案。
快速回顾
| 文章 | 核心内容 |
|---|---|
| 第一篇 | WMS整体业务流程、技术栈、项目定位 |
| 第二篇 | 20+张核心业务表设计、库存模型、核心业务SQL |
| 第三篇 | 高并发库存扣减、三种锁方案、面试并发难题解决 |
| 第四篇 | 库存模块面试题与项目亮点总结 |
| 第五篇(本文) | 入库流程源码级面试题精讲 |
一、入库流程整体回顾
基于项目源码,入库流程是WMS最核心的基础流程,支撑采购入库、退货入库、调拨入库等场景,整体分为四大核心阶段,全程事务可控、支持分批作业、状态全自动流转:
-
创建入库单:生成
WmsOrderHeader(入库单头)和WmsOrderLine(入库单明细),初始化待质检状态; -
质检与收货:调用
qualityInspec方法完成货物验收,生成待上架任务记录WmsAuditIn; -
上架入库:调用
onShelf方法执行库位上架,新增/更新即时库存,生成上架流水; -
状态闭环:根据收货、上架完成情况,自动更新单据行、单据头的完整业务状态。
二、入库流程核心面试题(15道完整版)
Q1:请结合项目源码,描述WMS中完整的入库业务流程。
参考答案:
基于项目源码,完整入库流程由三个核心Service方法串联实现,全程基于Spring事务保障数据一致性,无数据脏读、数据错乱问题。
① 创建入库单(WmsOrderHeaderServiceImpl.saveWmsOrderHeader)
// 生成唯一入库单号:类型编码 + 年月日 + 当日自增序号
wmsOrderHeader.setOrderNum(orderTypeCode + yyyyMMdd + "-" + String.format("%04d", count + 1));
// 初始化单据状态:待质检
wmsOrderHeader.setOrderStatus(CommonWms.WAIT_FOR_CHECK);
// 保存入库单头 & 批量保存入库明细行
② 质检收货、生成待上架数据(WmsOrderLineServiceImpl.qualityInspec)
// 1. 前置校验:防止重复收货、超量收货
// 2. 生成待上架任务记录
auditIn.setAuditCount(验收数量);
auditIn.setShelfSyCount(验收数量); // 初始化剩余上架数量
auditIn.setShelfStatus(CommonWms.WAIT_FOR_SHELF);
wmsAuditInMapper.insert(auditIn);
// 3. 更新订单行已收数量、剩余数量
// 4. 驱动单据状态流转
③ 库位上架、更新库存(WmsAuditInServiceImpl.onShelf)
@Transactional(rollbackFor = Exception.class)
public void onShelf(WmsAuditIn wmsAuditInvo) {
// 1. 校验上架记录合法性、上架数量不超限
// 2. 更新待上架表:累加已上架、扣减剩余上架数量
// 3. 插入已上架流水记录 WmsStockIn
// 4. 悲观锁更新/新增即时库存
updateInventoryWithLock(auditIn, wmsAuditInvo, ciAuditCount);
// 5. 最终更新单据完成状态
}
Q2:入库单号如何生成?为什么要这样设计?
参考答案:
源码生成规则:
wmsOrderHeader.setOrderNum(
orderTypeCode + DateUtils.date2Str(new SimpleDateFormat("yyyyMMdd"))
+ "-" + String.format("%04d", count + 1)
);
// 示例:RK20240515-0001(RK代表入库单)
设计优势:
-
高可读性:通过单号可直接识别单据类型、业务日期、流水序号;
-
方便检索:支持按日期、单据类型快速筛选数据;
-
全局唯一:同日期同类型自增序号,彻底避免单号重复;
-
易于扩展:自带日期维度,后续可无缝实现按月分表、数据归档。
Q3:质检环节如何防止重复收货、超量收货?源码如何实现?
参考答案:
项目通过双重字段校验杜绝重复收货和超收问题:
// 1. 整单收完拦截,禁止重复收货
if (wmsOrderLinevo.getGoodsCount().equals(wmsOrderLine.getGoodsDjCount())) {
throw new JeecgBootException("物料已收完,不允许再次收货");
}
// 2. 校验本次验收数量不能大于剩余可收数量
if (Convert.toInt(NumberUtil.sub(goodsYsCount, wmsOrderLinevo.getGoodsSyCount())) > 0) {
throw new JeecgBootException("验收数量不能大于剩余数量");
}
核心设计:通过 goodsDjCount(已收数量)、goodsSyCount(剩余待收数量)双字段动态校验,每一次收货都做幂等校验,保证数据严谨。
Q4:待上架表为什么同时设计已上架、剩余上架两个数量字段?
参考答案:
核心目的是支持分批上架,适配仓库真实作业场景:
-
shelfDjCount(已上架数量):记录累计上架总量,用于数据追溯、对账统计、进度展示;
-
shelfSyCount(剩余上架数量):记录未完成上架数量,用于判断是否存在待作业任务、控制单据状态流转。
核心更新逻辑:
String newShelfDjCount = NumberUtil.add(ciAuditCount, auditIn.getShelfDjCount());
String newShelfSyCount = NumberUtil.sub(auditIn.getAuditCount(), newShelfDjCount);
当剩余上架数量为0时,系统自动将单据状态更新为「已上架完成」。
Q5:上架环节如何保证库存数据一致性?结合源码说明
参考答案:
项目通过事务+悲观锁双重机制保障库存强一致性:
-
核心上架方法添加
@Transactional全局事务,待上架更新、上架流水新增、库存变更、单据状态更新,多表操作原子执行,异常自动回滚; -
库存查询使用
selectForUpdate行级悲观锁,锁定库存维度数据,杜绝并发上架导致的数据覆盖、库存错乱; -
库存更新后校验SQL影响行数,更新失败主动抛异常回滚。
Q6:上架时库存存在则更新、不存在则新增,源码如何实现?有什么优化方案?
参考答案:
原生实现逻辑:先锁查询、再判断新增或更新
// 悲观锁锁定当前维度库存
WmsInventory inventory = wmsInventoryMapper.selectForUpdate(...);
if (inventory != null) {
// 库存存在:数量累加更新
inventory.setBaseCount(NumberUtil.add(inventory.getBaseCount(), ciAuditCount));
wmsInventoryMapper.updateById(inventory);
} else {
// 库存不存在:新建库存记录
wmsInventoryMapper.insert(newInventory);
}
优化方案:使用 ON DUPLICATE KEY UPDATE 语法,单SQL实现存在更新、不存在新增,减少一次数据库查询,提升并发性能。
Q7:入库单完整状态有哪些?业务状态如何流转?
参考答案:
| 状态常量 | 状态含义 | 触发时机 |
|---|---|---|
| WAIT_FOR_CHECK | 待质检 | 入库单创建完成 |
| BEGIN_FOR_CHECK | 质检中 | 任意明细行开始收货质检 |
| END_FOR_CHECK | 质检完成 | 所有明细行收货完毕 |
| WAIT_FOR_SHELF | 待上架 | 生成待上架任务 |
| BEGIN_FOR_SHELF | 上架中 | 开始执行库位上架 |
| END_FOR_SHELF | 已完成 | 所有货物上架完毕 |
Q8:如何防止上架数量超过剩余待上架数量?
参考答案:
采用业务层校验 + 数据库层兜底双重防护:
1. 业务层前置拦截
private void validateShelfQuantity(WmsAuditIn auditIn, String ciAuditCount) {
if (Convert.toInt(NumberUtil.sub(ciAuditCount, auditIn.getShelfSyCount())) > 0) {
throw new JeecgBootException("上架数量不能大于上架剩余数量");
}
}
2. 数据库更新兜底
UPDATE wms_audit_in
SET shelf_sy_count = shelf_sy_count - #{qty}, shelf_dj_count = shelf_dj_count + #{qty}
WHERE id = #{id} AND shelf_sy_count >= #{qty}
Q9:如何设计入库API对接上游ERP系统?
参考答案:
系统设计标准化RESTful接口,实现与ERP无缝对接,支持ASN预入库、状态回调、单据查询:
| 接口地址 | 请求方式 | 接口说明 |
|---|---|---|
| /api/inbound/order/create | POST | ERP推送预入库单(ASN) |
| /api/inbound/order/cancel | POST | 取消未完成入库单 |
| /api/inbound/order/query | GET | 查询入库单状态 |
| /api/inbound/receive/confirm | POST | 收货结果回调 |
| /api/inbound/shelf/confirm | POST | 上架完成回调 |
| 核心设计:支持单号幂等、批量操作、全链路日志、双向回调通知。 |
Q10:上架遇到库位不足、物料错放如何处理?
参考答案:
1. 库位容量不足
系统校验库位最大存放容量,超限直接拦截;支持手动更换库位、系统智能推荐空闲库位。
2. 物料错放调整
封装库存转移方法,支持库位、箱码、托盘码变更,全程留痕追溯:
@Transactional
public void transferInventory(String inventoryId, String newKwCode, String newBinCode, String newTrayCode) {
WmsInventory inventory = wmsInventoryMapper.selectForUpdateById(inventoryId);
saveChangeLog(inventory, newKwCode, newBinCode, newTrayCode);
inventory.setKwCode(newKwCode);
inventory.setBinCode(newBinCode);
inventory.setTrayCode(newTrayCode);
wmsInventoryMapper.updateById(inventory);
}
Q11:入库流程如何自动生成物料批次、生产日期与有效期?
参考答案:
系统支持三种批次生成策略,适配不同业务场景:
-
手动录入:质检环节人工维护生产日期、有效期、批次号;
-
扫码解析:PDA扫码自动解析物料条码中的批次、生产日期信息;
-
系统默认生成:无数据时,取当前日期为生产日期,根据物料保质期自动推算有效期。
核心存储字段:
goods_pro_date VARCHAR(32) COMMENT '生产日期',
goods_batch VARCHAR(32) COMMENT '批次号'
Q12:如何处理无条码、箱码破损的物料入库场景?
参考答案:
系统做了柔性兼容设计,避免无条码物料无法入库:
-
支持手动输入箱码、托盘码,人工补录标签信息;
-
支持系统生成临时条码(TEMP+时间戳),后续可补打替换;
-
箱码、托盘码字段允许为空,不阻塞正常入库流程。
Q13:质检不良品如何走退货流程?数据如何保证一致?
参考答案:
-
质检不合格物料标记
qc_mark=BAD,单独上架至不良品专属库区; -
新建退货出库单,关联原入库单号,实现业务溯源;
-
从不良品库区下架扣减库存,生成退货流水记录;
-
退货全程开启事务,保证库存扣减、单据更新、流水记录原子性,数据可回滚。
Q14:如何通过锁机制防止入库单并发重复操作?
参考答案:
项目采用多层锁机制保障并发安全:
-
库存更新使用数据库悲观锁,锁定库存维度行数据;
-
待上架表引入乐观锁version,防止重复上架、重复更新;
-
分布式场景使用Redis分布式锁,锁定单号维度,防止多端并发操作。
UPDATE wms_audit_in
SET shelf_dj_count = shelf_dj_count + #{qty}, version = version + 1
WHERE id = #{id} AND version = #{oldVersion}
Q15:评价当前入库源码优缺点,并给出优化方案
参考答案:
✅ 优点
-
流程完整闭环:覆盖建单、质检、待上架、上架、库存更新全链路;
-
事务机制完善,杜绝多表数据不一致;
-
原生支持分批收货、分批上架,适配真实仓储作业;
-
状态机流转清晰,业务可追溯、可排查。
❌ 现存不足
-
待上架更新缺少数量条件兜底,极端场景存在超上架风险;
-
悲观锁未做超时、死锁规避策略;
-
缺少通用库存流水表,变更追溯能力弱;
-
核心业务方法臃肿,硬编码过多,可维护性差。
💡 优化方案
// 1. 增加数量条件兜底更新
int updated = wmsAuditInMapper.update(null,
Wrappers.<WmsAuditIn>lambdaUpdate()
.setSql("shelf_dj_count = shelf_dj_count + " + qty)
.setSql("shelf_sy_count = shelf_sy_count - " + qty)
.eq(WmsAuditIn::getId, id)
.ge(WmsAuditIn::getShelfSyCount, qty));
// 2. 新增库存流水记录,全程追溯
insertInventoryLog(inventoryId, "上架", beforeQty, afterQty, auditIn.getOrderNum());
// 3. 大方法拆分:校验、库存更新、日志记录解耦
三、入库流程核心表结构回顾
| 表名 | 核心作用 | 关键字段 |
|---|---|---|
| wms_order_header | 入库单头信息 | order_num、order_status |
| wms_order_line | 入库单明细 | goods_count、goods_dj_count、goods_sy_count、line_status |
| wms_audit_in | 待上架任务表 | audit_count、shelf_dj_count、shelf_sy_count、shelf_status |
| wms_stock_in | 上架流水表 | shelf_dj_count、audit_id、rel_order_num |
| wms_inventory | 即时库存表 | base_count、goods_batch、goods_pro_date、kw_code、qc_mark |
四、快速上手与项目地址
3分钟快速启动项目
# 克隆开源项目代码
git clone https://gitee.com/jeeslee/wms.git
-
执行数据库脚本:
docs/sql/wms.sql -
修改
application.yml数据库、Redis连接配置 -
启动项目
mvn spring-boot:run
开源项目地址
⭐ 后端WMS源码:https://gitee.com/jeeslee/wms
⭐ 前端Vue3源码:https://gitee.com/li_tongs/jeecgboot-vue3
📚 上一篇:WMS仓储系统(四)—— 库存模块面试题与项目亮点(面试必看)
📚 下一篇预告:WMS仓储系统(六)—— 出库流程面试题精讲(项目实战篇)
本文基于真实开源项目源码,全覆盖讲解入库流程业务、源码逻辑、面试高频考点,适合简历优化、面试突击、项目复盘。
更多推荐




所有评论(0)