# v8-export-import 详细参考 3

> 按需读取；本文件由 SKILL.md 的原章节无损拆分。

<!-- microi-progressive:chunk id=v8-export-import-011 sha256=a98c3b7c70f039fdd37128c3254acebd6fb527e78900f8fb38294e03baca083e -->
## 安全 / 性能注意

- ❌ 不要在循环中逐条 `AddFormData` 而不传 `V8.DbTrans`：每条独立事务，性能差且部分失败会留脏数据
- ✅ 传 `V8.DbTrans` 让所有插入在同一事务，失败自动回滚
- ✅ 大文件（>1万行）建议拆批 `AddTableData` 批量插入
- ✅ 校验字段长度、类型、必填，防脏数据
- ✅ 接口引擎要返回文件，必须在配置中开启【响应文件】
- ✅ 进度 Key 用 `Microi:${V8.OsClient}:Category:Key` 命名，区分租户

### 复盘：应用包同步物理字段时直接 ALTER 导致安装异常

- 触发场景：目标租户安装或升级应用包时，已有长文本配置超过来源包的 `varchar(N)` 长度，或历史数值字段仍以空字符串保存，`MODIFY COLUMN` 分别报 `Data too long`、`Incorrect integer value: ''`。
- 根因：导入器把来源库物理字段定义直接覆盖到目标库，没有判断是否属于缩窄变更，也没有在文本转数值前兼容平台历史空值。
- 通用规则：物理字段同步必须只扩宽、不缩窄；目标库已有更宽文本类型或更大整数类型时保留目标类型。文本转数值前仅可把空字符串规范为 `NULL`，发现非空非数字值必须中止该字段迁移并报告数量，禁止静默转为 `0` 或截断数据。只要导入日志存在异常，就不得写入“安装成功”的应用版本记录。
- 自动化检查：准备“超长 JSON + 空字符串数值 + 非数字脏值”三类旧库样本，重复安装同一应用包；前两类应无异常且数据不丢失，第三类应明确失败且原数据保持不变。

### 复盘：重复字段与业务 Key 改名破坏应用包幂等安装

- 触发场景：应用包中同一张表出现两个同名字段时，第一次 `ADD COLUMN` 成功、第二次报 `Duplicate column name`；在线应用保留原 Id 但修改 `AppKey/MsKey` 后，目标库按新 Key 查不到记录，又用原 Id 执行 INSERT，报主键重复。
- 根因：安装器只在阶段开始时读取一次物理字段快照，新增后没有更新；同时只按业务 Key 判断在线应用是否存在，没有优先按稳定 Id 对齐，也没有迁移旧 Key 关联的微服务和页面。
- 通用规则：包内字段必须按 `TableId + lower(Name)` 去重，新增物理列后立刻更新内存快照；并发或历史残留造成的重复列错误需回查后按幂等跳过。在线应用、微服务及版本数据必须先按 Id、再按业务 Key 查找；Id 命中而 Key 变化时更新原记录并沿用原 Id，把关联页面统一迁移到新 Key，禁止再次 INSERT。
- 自动化检查：构造“同表重复字段”和“固定 AppId、AppKey 从 old-key 改为 new-key”两个包，连续安装至少两次；每次都应 `Code=1`，物理列、应用、微服务均只有一条，所有页面引用新 Key 且保留原关联 Id。

### 复盘：租户历史残留绕过 FormEngine 查询后触发主键和重命名冲突

- 触发场景：同一应用包在平台主租户、平台子租户和客户独立部署中表现不同；字段导入报 `diy_field.PRIMARY` 重复，字段改名报目标物理列已存在，旧版微服务包还可能调用不存在的 ZIP 哈希函数。
- 根因：导入器只用 FormEngine 判断记录是否存在，软删除、空 OsClient 或历史异常记录会被过滤，但物理主键仍在；字段重命名只判断元数据变化，没有在 DDL 前分别检查源列和目标列；修复只写入某个租户接口引擎，没有让全局升级器按导入器能力重新刷新。
- 通用规则：元数据 UPSERT 必须在 FormEngine 未命中时直查物理主键；同一逻辑字段应恢复后更新，真正的 Id 冲突应生成目标 Id 并建立包内引用映射。执行 `CHANGE COLUMN` 前必须检查源列存在且目标列不存在，目标列已存在时按幂等跳过。导入器修复必须同时更新官方资源、目标租户和自动升级能力检测，禁止只依赖全局版本号。
- 自动化检查：准备软删除主键、空租户主键、同表目标列已存在、旧导入器函数缺失四类租户快照；连续安装系统设置、首页数据包和含源码 ZIP 的微服务包两次，均应 `Code=1` 且版本记录只反映无异常安装。再把全局版本号设为高于修复版本、导入器降级，验证启动升级仍会按能力标记自动恢复导入器且不降低全局版本号。

### 复盘：数据库空库导出日期区域化且导入器吞错导致延迟误报

- 触发场景：空库 SQL 把 MySQL `datetime` 导出成 `05/12/2026 12:50:33` 等区域格式；导入器逐句执行时跳过或吞掉失败语句，后续初始化才误报“缺少默认 admin 用户”。
- 根因：导出器只按 CLR 返回类型格式化，没有以 `information_schema.COLUMNS.DATA_TYPE` 为事实源；导入器把局部失败计数后仍返回成功，也没有在导入结束立即校验核心表和模板账号。
- 通用规则：数据库转储必须按真实物理列类型格式化 `date/datetime/timestamp`，统一输出 ISO 日期；完整 SQL 导入任一语句失败必须整体失败并保留原始数据库错误，禁止吞错继续。导入完成后立即校验核心表和模板账号，后端读取最新发布包时优先直读对象存储，避免 CDN 长缓存返回旧包。
- 自动化检查：制作并发布空库后校验 ZIP 哈希、SQL 中区域日期匹配数为 0、核心表和默认 `admin` 存在；再从真实注册页创建新租户，并使用新租户 `admin` 的初始密码登录一次，不能只验证发布任务或租户记录返回成功。
<!-- /microi-progressive:chunk -->
