金蝶云星空物料清单(BOM)增量同步到 MySQL 实战教程
这个策略解决什么问题
物料清单(BOM)从金蝶云星空推到下游 MySQL,看起来只是"取数+落库"。但 BOM 是树形结构,每个分录对应一个父子物料关系,一旦编码映射没设计、增量边界没掐住,3 个月后两边数字就对不上了,生产环节直接受影响。这条策略就是用增量+组织过滤的方式,把 ENG_BOM 表稳、按时、只拉该组织的数据落到 MySQL,做下游 MES、BI 的数据底座。
数据流向与字段映射
整体链路是 金蝶云星空 → 轻易云(Qeasy)中间层 → MySQL。源端 FormId 用 ENG_BOM,通过 executeBillQuery 拉取。关键字段对照如下(目标表 tp_jd_entry):
| 目标字段 | 源字段/规则 | 映射类型 | 说明 |
|---|---|---|---|
| FENTRYID | FTreeEntity_FENTRYID(FID) | DIRECT | 分录主键,作为 upsert 主键 |
| FNumber | FNumber | DIRECT | BOM 编码 |
| FName | FName | DIRECT | BOM 名称 |
| FBILLTYPE_FNumber / _FName | FBILLTYPE.FNumber / .FName | TRANSFORM | 单据类型,源端预提取 |
| FBOMCATEGORY_FNumber | FBOMCATEGORY | DIRECT/COLLECTION | 嵌套对象取 .FNumber |
| FBOMUSE_FNumber | FBOMUSE | DIRECT/COLLECTION | 同上 |
| FGroup_FNumber / _FName | FGroup.FNumber / .FName | TRANSFORM | 分组 |
| FMATERIALID | FMATERIALID.FNumber | TRANSFORM | 父物料编码 |
| FITEMNAME | FITEMNAME | DIRECT | 父物料名称 |
| FMATERIALIDCHILD | FMATERIALIDCHILD.FNumber | TRANSFORM | 子物料编码 |
| FCHILDITEMNAME | FCHILDITEMNAME | DIRECT | 子物料名称 |
| FNUMERATOR / FDENOMINATOR | 直接对应 | DIRECT | 用量分子/分母 |
| FSCRAPRATE / FISSUETYPE | 直接对应 | DIRECT | 损耗率、投料类型 |
| FCreateDate / FApproveDate / FForbidDate | 直接对应 | DIRECT | 关键业务时间戳 |
| FCreateOrgId / FUseOrgId | .FName | TRANSFORM | 创建/使用组织名称 |
| FModifyDate | FModifyDate | DIRECT | 增量游标字段 |
源端未映射的 FDocumentStatus、FForbidStatus 不进目标表,需要时可在源端预提取或后续补策略。
在轻易云上如何配置
在轻易云(Qeasy)集成平台里,这条策略核心是"源端读 + 目标端写"两个节点。
- 源端(读):金蝶云星空连接器,API 选
executeBillQuery,FormId 写ENG_BOM,请求体里把嵌套字段(如{{FBILLTYPE.FNumber}}、{{FMATERIALID.FNumber}})提前展平,目标表是扁平结构就不用再二次解析。 - 过滤条件:
FModifyDate>='{{LAST_SYNC_TIME|dateTime}}' and FUseOrgId.fnumber='TP000',既按修改时间增量,又按组织隔离。 - 分页:
Limit=2000,StartRow={{PAGINATION_START_ROW}},避免一次拉太多把源端压垮。 - 目标端(写):MySQL 连接器,执行方式选 SQL,
idCheck=true,以FENTRYID做唯一性校验,REPLACE INTO tp_jd_entry,单批 200 条。 - 编码映射:本策略不涉及跨方案
_findCollection,所有编码都在源端用{{对象.属性}}语法预提取,集中在一处管理,后续审计和改字段都方便。
实施步骤
分三步走,先打通,再稳跑,最后控频率。
-
建目标表与初始化主键 在 MySQL 准备好
tp_jd_entry,主键用FENTRYID,建好必要索引(BOM 编码、父物料编码、子物料编码)。先清空目标表做一次冷启动,确认字段类型和 BOM 实际取值对得上。 -
配置源端与目标端,做一次全量 源端把增量条件临时去掉,跑一次全量回灌,验证字段映射、组织过滤、分页逻辑都没问题。全量成功后再把
FModifyDate增量条件加回去,转入稳态。 -
调度编排(增量 + 时序)
- 源端读:
*/7 * * * *,每 7 分钟拉一次 - 目标端写:
3-59/7 * * * *,延后 3 分钟执行,保证先读后写 - 监控每次拉取量、写入量、失败条数,异常立刻告警
- 源端读:
稳妥起见,建议同时保留"全量触发"开关,业务大改或组织切换时一键重跑。
踩坑复盘
-
BOM 是树形结构,主键别用 BOM 头 FID 典型错误是拿表头
FID当主键 upsert,结果多级 BOM 永远只留第一条。正确做法是用分录 IDFTreeEntity_FENTRYID,每个父子关系独立一行,这也是目标表用FENTRYID做主键的原因。 -
嵌套对象不在源端展平,目标端就崩 金蝶返回的
FBILLTYPE、FGroup是{FNumber, FName}结构。如果在源端请求里不写{{FBILLTYPE.FNumber}}提前展平,落到 MySQL 就是 JSON 字符串,后续统计和联表全废。我们在源端配置阶段就把所有*_FNumber、*_FName平铺好。 -
组织过滤写错位置
FUseOrgId.fnumber='TP000'必须放在FilterString里,而不是在后置脚本里过滤。后置过滤意味着已经把别的组织数据拉回来了,既浪费接口配额,也容易在脚本里漏写。 -
调度同点,写入被读覆盖 源端目标端用同一个
*/7 * * * *时,会出现"读完还没写完,新一轮又开始读"的毛刺。稳妥的做法是源端*/7,目标端3-59/7,让写入比读取晚 3 分钟,时序稳定。 -
目标表没有唯一性约束,重复行越积越多
idCheck=true配REPLACE INTO是双保险。如果哪天有人手抖把idCheck关了,又没有数据库唯一索引,数据就会越来越脏,排查极难。建议在表上加唯一索引,平台层和库层双重兜底。
适用场景与不适用场景
适用:金蝶云星空作为 ERP 主数据源,下游 MES、BI、自建系统需要稳定的 BOM 基础资料,且有明确的多组织隔离要求,数据量在每 7 分钟一次的窗口内能消化。
不适用:需要跨多套账套汇总 BOM 的场景(建议走 _findCollection 集中映射);源端 BOM 结构频繁自定义、需要大量 _function 表达式二次加工的场景;以及对实时性要求秒级的场景,这种建议走变更通知而非轮询。