想做无流程引擎的纯净库,导入却炸 already exists、db version null:Forge Admin 跳过 act_* 还得跳 flw_*

0 阅读6分钟

Forge Admin 是一套 Java / Spring Boot / Vue 的开源后台框架,自带流程(Flowable)、多租户、低代码与社区「按版本纯净版」初始化 SQL。开源仓库:Gitee ForgeLab/forge-admin(GitHub 镜像:yaomindong1996/forge-admin)。演示环境可参考文档站说明。

想给社区一份「干净、可空库导入、不含流程运行垃圾」的 SQL——听起来只是 mysqldump 多写几条 ignore。结果现场是这样的:

  1. 空库导入「纯净版」看起来成功了,一启动却炸:Table 'flw_ru_batch' already exists;
  2. 紧接着又是 FlowableWrongDbException: version mismatch … db version is null;
  3. 手忙脚乱从 dump 里「删掉 flw_*」之后,发现 admin / 字典 / 参数的 INSERT 也没了。

这不是发版公告,是 Forge 在 2026-10-13~14 一串真实提交里,把「半套 Flowable 表」钉进 dump-safe-full.sh、skill 文档和 pitfalls 的过程。读完你能带走三条硬规则:引擎表两套前缀必须一起跳过;框架 *_version 不能用宽松正则误伤;事后手工剥 SQL 比改脚本更危险。

TL;DR(可先收藏)

  1. Flowable 不止 act_*:事件注册等还有 flw_*(如 flw_ru_batch、flw_event_*、flw_channel_definition)。
  2. 社区纯净版 不要导出 引擎表:由 Admin/Flow 首次启动自动建;半套表比「完全没有」更糟。
  3. dump-safe-full.sh 定稿规则:full_ignore_regex="^act_|^flw_"(commit 1dcf6607)。
  4. 只跳 ^act_ → 留下 flw_* → 引擎再 CREATE → already exists,且常无 act_ge_property.schema.version → db version is null。
  5. 不要用 (^|_)version$「顺便」忽略:会误伤 ai_business_extension_version、ai_crud_config_version、sys_flow_model_version 等。
  6. 事后从 SQL 文件剥 flw_* 必须按表块删,不能从第一个 flw_* 一路 skip 到文件尾——mysqldump 按表名排序,后面往往是 sys_*。

版本与提交矩阵(本稿场景)

组件 / 产物说明
流程引擎Flowable(社区纯净版策略:不带引擎表;启动再建)
导出脚本forge-server/scripts/db/dump-safe-full.sh
导出规范.agents/skills/forge-project-init/references/pure-sql-export.md
踩坑备忘code-copilot/memory/pitfalls/flow.md
发布物forge-server/db/backup/ForgeAdmin-纯净版-V1.2.0.sql
关键提交88d17508 → fc753e11 → ad5da3d6 → 1dcf6607(2026-10-13~14,上海时区)

下面按「现象 → 根因 → Forge 怎么改」拆三段,并把三次返工串成一条时间线。重点在框架落地,不在背 SQL 表名大全。


现象:想要「无流程表」,却导入后启动连环炸

按源码推演(发布前请作者用空库验证):运营侧从已跑过 Flyway 的测试库,经 clean-db.sh 清理再 dump-safe-full.sh,产出「ForgeAdmin-纯净版-Vx.y.z.sql」。目标在 skill 里写得很清楚——空库一次导入成功、有默认租户与超级管理员 admin、导入后启动前 information_schema 里 act_% / flw_% 应为 0 张。

但当 full_ignore_regex 还只写 ^act_ 时,flw_ru_batch、flw_event_*、flw_channel_definition 等会进 dump。空库导入后一启动,日志常常是两连击:

SQLSyntaxErrorException: Table 'flw_ru_batch' already exists
FlowableWrongDbException: version mismatch: library version is '7.0.1.1', db version is null

第一句好懂:引擎 schema 脚本还要执行 CREATE TABLE,库里却已经有同名表。第二句更阴:有一部分 flw_*,却读不到完整的 act_ge_property.schema.version——半套表把引擎推进「既不能当空库初始化、又不能当已升级库」的夹缝。排障同学若只搜 already exists,很容易去删表、改字符集、甚至怀疑 Flyway 历史,而漏掉「导出 ignore 规则写窄了」这一层。


根因一:Flowable 是两套表前缀,不是「只要 act_」

仓库 pitfalls(发现日期 2026-10-13,commit 88d17508)写得很直白:

社区纯净版从测试库 dump 时,full_ignore_regex 只写了 ^act_,把 flw_ru_batch、flw_event_*、flw_channel_definition 等带进 SQL。
根因:Flowable 表必须整套由启动创建。半套 flw_* + 无 act_ge_property 比「完全没有流程表」更糟。

同一次提交把脚本改成同时跳过 flw_*,并新增 pure-sql-export.md。文档还划了一条红线:禁止在导出后手工追加 INSERT INTO act_ge_property / act_id_property——有 INSERT、无建表,Navicat / mysql 会报 1146 Table '….act_ge_property' doesn't exist。

这里有一个容易混的语义差,必须分开记:

  • clean-db.sh 库内清理:运行库里已经有流程表时,仍可保留 ACT_GE_PROPERTY / ACT_ID_PROPERTY 等属性行,再截断其它运行表——那是给「已存在引擎」的环境用的。
  • 社区纯净版导出:不要把引擎 DDL/DML 带进下载文件;官方「全量初始化 SQL」本身也不带完整 act_* / flw_* 结构,靠应用首次启动创建。

旁支(commit fc753e11):同一测试库若先被 Flowable 8 写过再回退 7.x,只改 act_ge_property 版本号不够——Liquibase 托管的 flw_* / act_app_* / act_cmmn_* / act_dmn_* 等会再撞 already exists。与「纯净导出」是不同坑,但共享同一直觉:引擎主版本、库内 schema 标记、changelog 必须成套,半升级/半回退最伤。

调用链可以压成四行(便于贴到团队群):

dump 只 ignore ^act_
  → SQL 文件带半套 flw_*(无完整 act_ge_property 版本契约)
    → 启动时引擎再 CREATE / 读 schema.version
      → already exists + db version is null

根因二:错误的 version 忽略会误伤框架表

88d17508 一度写成:

full_ignore_regex="^act_|^flw_|(^|_)version$"

意图可能是「跳过无关 version 表」。commit 1dcf6607(2026-10-14)证明:该正则会匹配所有以 _version 结尾的框架表。导入纯净版后,低代码扩展一写版本、CRUD 一发版、流程模型一存历史,就会缺表。典型受害者包括:

  • ai_business_extension_version
  • ai_business_application_version
  • ai_crud_config_version
  • sys_flow_model_version / sys_flow_form_version
  • sys_print_template_version
  • …

定稿注释与规则变为(脚本约 L229–L231,commit 1dcf6607):

# Flowable 引擎表由应用首次启动创建;社区纯净版/安全全量导出不得带 act_*/flw_*
# 注意:不要用 (^|_)version$ —— 会误伤 ai_business_extension_version 等框架表
full_ignore_regex="^act_|^flw_"

ignore-regex.png

pure-sql-export.md 与 forge-project-init SKILL 同步:Never 再加 (^|_)version$。V1.2.0 SQL 补回上述 *_version 的空结构 DDL(可无业务数据)——纯净版要的是「能跑起来的骨架」,不是「演示数据拉满」。

这是典型的「正则写宽了」事故:本想少导出一点噪音,结果把框架契约表当成噪音。和只跳 act_* 一样,都属于 ignore 规则的产品语义没钉死。


根因三:手工「删 flw_*」可能顺手删掉 admin

commit ad5da3d6 记录了另一次返工:旧 dump 仍含 flw_* 时,有人用编辑器/脚本从第一个 flw_* 数据段一路 skip 到文件尾。mysqldump 的 data 段按表名排序,flw_* 后面往往是 sys_*——于是 sys_user、sys_dict_data、sys_config、sys_resource 的 INSERT 全部消失。导入后「库能建起来,但登不进 admin、菜单字典全空」。

文档因此补了两条硬约束:

  1. 删除时必须按表一块一块删(每个 Table structure / Dumping data 块各自结束);
  2. 优先依赖已修复的 dump-safe-full.sh,避免事后剥离。

验收清单(导入空库后):

检查项期望
导入 ERROR0
sys_user / sys_tenant / sys_role各 1 行,admin
sys_dict_type / sys_dict_data / sys_config / sys_resource有数据
forge_schema_history有数据,版本与源库一致
act_% / flw_% 表数量(启动前)0
全文检索无 AKID / LTAI / 真实库密码 / 云密钥

Forge 怎么落地:脚本 + skill + pitfalls 三件套

框架侧没有把规则只写在某次聊天记录里,而是收敛到三处,保证「下次再导纯净版」可重复:

1)导出流水线(必须在克隆库上操作)

# 1) 克隆测试库 → 临时库(禁止对共享库直接 --execute 清理)
mysqldump … forge_admin | mysql … forge_admin_vXXX_pure

# 2) 清理成模板库(forge-server 下)
MYSQL_PWD=*** bash scripts/db/clean-db.sh \
  --host … --database forge_admin_vXXX_pure --user … --execute --yes

# 3) 安全导出(须跳过 act_* 与 flw_*)
MYSQL_PWD=*** bash scripts/db/dump-safe-full.sh \
  --host … --database forge_admin_vXXX_pure --user … \
  --output /tmp/forge-admin-pure-base.sql

# 4) 可选追加:forge_schema_history + 本地无密钥的 sys_file_storage_config
# 5) 清洗 installed_by(如 rdsroot→flyway);全文确认无 CREATE TABLE `flw_` / `act_`
#    且仍有 INSERT INTO `sys_user` / 字典 / 参数

export-pipeline.png

文件名建议:ForgeAdmin-纯净版-V{版本}.sql。大 SQL 默认不要误提交进业务仓库,除非明确要求;文档站走运营后台「纯净版 SQL」上传即可。

2)已误导入带 flw_* 的库(急救)

按源码推演,可在该目标库按实际表名调整后删除残留 flw_*(示例见 pure-sql-export.md:flw_ru_batch、flw_event_*、flw_channel_definition、flw_ev_databasechangelog* 等),再重启 Admin/Flow 让引擎重建。更稳妥:空库重导已去掉全部 flw_/act_ 的纯净版文件——比在脏库上「外科手术」更少二次踩坑。

3)对照表(可收藏)

做法典型结果Forge 定稿
只 ignore ^act_半套 flw_* → already exists + version null不够
ignore ^act_|^flw_|(^|_)version$引擎表对了,框架 *_version 缺表禁止 version 段
ignore ^act_|^flw_启动前 0 张引擎表;框架版本表保留定稿
手工从 flw_* skip 到 EOF可能误删 sys_* INSERT按表块删或重导
导出后追加 act_ge_property INSERT1146 表不存在禁止
8 污染库只改 version 回 7.xLiquibase 表再 already exists另见版本混用 pitfalls

三次返工时间线(方便对照 commit)

顺序SHA(短)做了什么
1fc753e11记录 Flowable 8→7 版本混用;纳入纯净版 V1.2.0 SQL
288d17508dump 增加跳过 flw_*;写 pure-sql-export;从 V1.2.0 去掉半套 flw_*
3ad5da3d6修复剥离时误删的 admin/字典/参数等基础数据
41dcf6607去掉 `(^_)version$;补回框架 *versionDDL;定稿^act^flw_`

叙事上这是一条「想做对 → 规则偏窄 → 规则又偏宽 → 手工返工误伤」的完整闭环。对开源后台框架来说,导出脚本的正则就是产品契约:写错一次,社区下载方全员踩坑。


可带走的自查清单

导出或审核「纯净版 SQL」前,建议按序过一遍:

  1. 全文检索:是否还有 CREATE TABLE \flw_/CREATE TABLE `act_`?
  2. 是否误带 INSERT INTO act_ge_property / act_id_property?
  3. dump-safe-full.sh 的 full_ignore_regex 是否仅为 ^act_|^flw_?
  4. 是否没有 (^|_)version$?纯净版是否含 CREATE TABLE \ai_business_extension_version`` 等?
  5. 是否有 INSERT INTO \sys_user`` / 字典 / 参数 / 资源?
  6. 空库导入后、启动前:act_%/flw_% 表数是否为 0?
  7. 启动后:引擎表是否由应用创建?Flyway 是否显示已是最新?admin / 123456(默认)能否登录?本地上传配置是否仅 local、无云密钥?

做完这七步,再谈「要不要追加演示菜单、要不要带低代码样例表」——后者是产品选择,前者是能不能启动的底线。


框架视角:为什么规则要进脚本,而不是进 README 一句「注意」

若只在文档写「导出时请手动排除流程表」,每个运营同学、每个版本、每次克隆库都会重新发明一套 ignore 列表,最终一定有人只记得 act_*。Forge 的选择是:

  • 脚本默认正确:dump-safe-full.sh 的 full_ignore_regex 就是契约;
  • skill 可执行:forge-project-init 的纯净导出步骤可被 agent / 人复跑;
  • pitfalls 可检索:现场报错关键词能搜回「半套 flw_*」「version 正则误伤」。

这和「业务模块里临时手改一份 SQL」是两种产品观。后者能糊过一次发布,前者才能让社区下载页长期可点。


和本系列其它文的差异

  • 不是「Boot4 缺 applicationTaskExecutor + Sa-Token 旧 Session」(10-13 已发);
  • 不是「MyBatis-Plus 分页 COUNT(*) 解析失败」(10-12);
  • 不是「插件独立 Flyway / FeatureGate / 离线许可证」(10-11);
  • 不是「单据打印两层校验 / 头像预签名」(更早);
  • 本篇切口是 社区初始化 SQL 的表前缀契约:act_* 与 flw_* 必须成套跳过,框架 *_version 不能被正则误伤,手工剥离不能误删 sys_*。

Forge Admin 把这些写进导出脚本、skill 与 pitfalls:业务侧下载纯净版时少踩「半套引擎表」的坑。源码检索关键字:dump-safe-full.sh、full_ignore_regex、pure-sql-export.md、commits 88d17508 / ad5da3d6 / 1dcf6607。