生产作业记录导入总丢历史数据?幂等性修复与状态保护实战方案
生产作业记录导入总丢历史数据?幂等性修复与状态保护实战方案
去年我接手生产MES系统的作业记录导入模块,生产班组的紧急反馈几乎没断过:同一条熔炼记录导了两次;之前标成"炉甩"的废品工艺又溜回待处理列表;工艺员花了两小时填的质检结果被覆盖成空;甚至上个月删掉的异常记录也"复活"了。查下来根因就两条——导入逻辑既没做完整的幂等校验,也没对历史状态做保护,所有关联工艺被一股脑全量覆盖更新。
我定的核心规则很直白:重复导入只更新基础信息,历史的状态、时间戳、结果类字段全部冻结,删除态的工艺直接跳过。
先动幂等键。原来的唯一判断只用了订单号、炉号、流节号三个维度,漏了支号——同一条熔炼记录下不同支号的工艺是完全独立的,缺了支号,要么把不同支号错判成重复,要么让相同支号的重复导入漏网。升级后改成四个字段联合:只有订单号+炉号+流节号+支号完全一致,才判为重复走更新,否则作为新记录插入。
然后是工艺状态的分层处理。已软删、炉甩、硬删的工艺,直接跳过,不更新也不插入,杜绝删除态数据复活;处于进行中、待质检的工艺,只更新文件里提供的基础字段(原料批次、工艺参数),已经写好的状态、时间戳、质检结果冻结不动,禁止导入覆盖;文件里有、系统里没有的工艺,正常插入。
一个典型的翻车案例:某批次304不锈钢熔炼记录,支号2,第一次导入后工艺被班组标记成"炉甩",第二次导入时老逻辑直接把炉甩标记删了,还覆盖了之前记的杂质含量检测值,当月质检报表的数据就偏了。升级逻辑后,第二次导入会直接识别到该工艺处于炉甩状态,整条跳过更新,历史数据不受影响。
核心代码大致长这样(业务实体名做了泛化):
// 1. 幂等性判断:4字段联合唯一键校验
ProductionRecord existRecord = productionRecordMapper.selectOne(
Wrappers.<ProductionRecord>lambdaQuery()
.eq(ProductionRecord::getOrderNo, orderNo)
.eq(ProductionRecord::getFurnaceNo, furnaceNo)
.eq(ProductionRecord::getStreamNo, streamNo)
.eq(ProductionRecord::getBranchNo, branchNo) // 新增支号维度
);
if (existRecord != null) {
// 仅更新作业记录基础信息,不触碰关联工艺
updateBaseRecordInfo(existRecord, importData);
// 2. 关联工艺状态过滤处理
List<ProcessRecord> processList = importData.getProcessList();
processList.forEach(process -> {
// 跳过所有删除态/终止态工艺
if (process.getStatus() == ProcessStatus.DELETED
|| process.getStatus() == ProcessStatus.FURNACE_DISCARD
|| process.getStatus() == ProcessStatus.HARD_DELETED) {
return;
}
ProcessRecord existProcess = processMapper.selectOne(
Wrappers.<ProcessRecord>lambdaQuery()
.eq(ProcessRecord::getRecordId, existRecord.getId())
.eq(ProcessRecord::getProcessSeq, process.getProcessSeq())
);
if (existProcess != null) {
// 仅更新基础字段,冻结状态、时间戳、结果
existProcess.setMaterialBatch(process.getMaterialBatch());
existProcess.setProcessParam(process.getProcessParam());
// 以下字段禁止导入覆盖,注释掉更新逻辑
// existProcess.setStatus(process.getStatus());
// existProcess.setTestResult(process.getTestResult());
// existProcess.setUpdateTime(process.getUpdateTime());
processMapper.updateById(existProcess);
} else {
processMapper.insert(process);
}
});
return;
}
// 不存在则走新增逻辑
insertNewRecord(importData);
验证我设计了三组用例:重复导入完全相同的记录,确认只更基础信息、关联工艺的状态和结果不变;导入含已炉甩工艺的文件,确认炉甩工艺不被恢复、删除态不复活;导入含已修改质检结果的工艺,确认历史质检结果不被覆盖。上线跑了三个月,重复导入导致的数据异常降到0,班组每次导入后的核对时间从平均10分钟压到了1分钟以内。
这套方案落到两条经验上:工业数据导入的唯一键一定要贴业务实际,支号、批次号、炉次号这类细分维度漏一个,幂等校验就形同虚设;批量导入必须做"写入权限分层",基础信息可以动,状态、时间戳、人工修正的结果类字段得冻结,否则批量操作很容易污染掉人工维护的数据。删除态的数据更要在导入前就过滤掉,别等更新时再判断,从源头拦住死数据复活。

浙公网安备 33010602011771号