摘要:车间扫码报工经常遇到网络抖动、重复点击、手持终端重发。本文用一套常见的表结构和处理流程,说明报工接口如何做幂等去重、保证事务边界一致,以及失败后的补偿方式,适用于MES、WMS等扫码类业务系统。
一、问题从哪里来 手持终端在车间弱网环境下,请求超时后用户会再点一次,终端也可能自动重发。如果服务端每次都当新报工处理,同一工序的合格数会被累计两次,后面的完工判定、成本核算全部失真。解决思路是:让同一次业务动作无论请求多少次,结果只生效一次。
二、幂等的三种实现对比 方案|做法|优点|局限 唯一流水号|客户端为每次报工生成UUID,服务端对该字段建唯一索引|简单可靠,天然防重|终端必须在重试时沿用同一个流水号 业务键去重|以“工单号+工序号+操作人+时间窗口”判断重复|无需改终端|误判风险,同人连续两次合法报工会被拦 状态机校验|工序必须处于“进行中”才能报完工,已完工的拒绝|保证状态合法|只防止完工重复,不防数量重复累加 推荐:以唯一流水号为主,状态机校验为辅。
三、表结构与处理流程 报工记录表关键字段:id、request_no(唯一索引)、order_no、operation_no、good_qty、bad_qty、operator_id、report_time、device_id、status。 处理流程:
- 接口收到请求,先在同一事务内尝试插入报工记录,request_no 冲突则直接返回上一次的处理结果,不报错。
- 校验工单、工序状态、数量是否超过投入数。
- 更新工序累计合格数、不良数(用 update ... set good_qty = good_qty + ? 的原子写法,不要先读后写)。
- 以上步骤放在一个本地事务里,提交后再发消息通知下游(如ERP、WMS)。
四、事务边界与补偿 报工成功后要通知ERP回写,这一步不要放进同一事务。推荐“本地消息表”做法:在同一事务里写报工记录和一条待发送消息,由后台任务异步发送;发送失败按递增间隔重试,超过次数转人工。ERP侧用同一个 request_no 去重,保证重复到达不重复入账。若报工需要撤销,不删除原记录,而是写一条负数的冲销记录并关联原 request_no,保留审计链路。
五、常见问题 request_no 谁来生成?由终端在用户点击确认时生成,重试时沿用,换一次新的操作才换新号。 并发下数量会超吗?用原子更新加数量上限条件(累计数不超过投入数),更新行数为0则返回数量超限。 离线报工怎么办?终端本地存队列,联网后按顺序补传,每条沿用原 request_no,服务端按到达时间之外的 report_time 排序。 是否需要分布式事务?一般不需要,本地事务加消息表加幂等即可满足车间场景。
