
简介芋道源码 BPM 工作流模块的 MySQL 初始化 SQL 脚本适配 JDK17 环境面向需要在业务系统中集成或二次开发工作流能力的后端开发者。脚本内置了任务表、用户表、角色表、工作流定义表、流程实例与历史记录等 8 张核心数据表的建表语句及初始数据完整支撑流程定义、任务分配、审批流转、历史归档等环节帮助部署者跳过手工建表流程避免因遗漏字段或缺失初始化数据导致的运行问题快速完成数据库层准备。压缩包共 2 个文件包含一个 SQL 初始化脚本和一个 txt 说明文档后者对脚本用途和表结构进行补充整体仅 2KB轻量易用。已有 522 人学习下载。拿到后可直接导入 MySQL 执行配合芋道源码框架即可搭建 BPM 模块也可作为理解工作流表设计的学习样本适合项目初始化、环境搭建和源码阅读场景。1. BPM 工作流模块那张初始化 SQLMySQL 版本到底在初始化什么芋道源码这套 BPM 工作流模块底层引擎是 Flowable引擎自己的表以ACT_开头真正跟业务相关的流程分类、动态表单、任务分配规则、流程实例镜像全都落在bpm_开头的业务表里。初始化 SQLMySQL 版本要做的不是把 Flowable 的引擎表手写出来而是把bpm_业务表、菜单权限、数据字典、演示 OA 数据一次铺到位。接手这套代码的人最常见的问题就出在这里以为“初始化 SQL 全部建表”拿脚本去跑结果启动后才发现 ACT_ 表由引擎自动建但bpm_category、bpm_form一张都没有工作流模块直接停在半瘫状态。这篇文章从“它到底管哪些表”讲起一直讲到导入命令、参数调整和踩坑记录适合正在部署芋道 BPM 模块、或者准备把工作流从 Demo 迁到自己业务上的后端和全栈工程师。2. 拆 BPM 初始化 SQL哪一块属于 Flowable、哪一块必须建在 bpm_ 表先建立一个整体判断这套 BPM 工作流模块部署到 MySQL 上以后一个数据库实例里同时存在两套表。一套是 Flowable 引擎管理的ACT_RE_、ACT_RU_、ACT_HI_系列另一套是芋道在引擎外层做的业务封装表统一bpm_前缀。初始化 SQL 的职责边界就在这里它只管bpm_表和少量系统表数据不碰ACT_系列。理解这个边界后面所有的导入和排错才有坐标系。2.1 Flowable 自动建表与初始化 SQL 建表职责边界Flowable 自带 schema 管理能力。应用启动时只要数据源连接成功引擎组件会检测自己版本对应的数据库表结构缺表就按内置 DDL 补建版本不一致就直接抛异常阻止启动。所以常见做法是引擎表交给 Flowable 的自动建表策略处理初始化 SQL 不要越权去建ACT_表。你手动把别人环境里导出的ACT_GE_PROPERTY、ACT_RE_MODEL拿过来灌进 MySQL反而把风险背到自己身上Flowable 升级后库里旧表版本对不上启动日志直接报 schema 版本不匹配这种环境问题比业务代码问题难排查得多。芋道这类框架一般在配置文件里暴露引擎建表策略开发环境用一个“自动更新”的模式启动时缺什么补什么。如果这个策略被设置成关闭初始化 SQL 又没建ACT_*表启动日志就会出现某个ACT_表不存在的错误这就是很多同学第一次跑 BPM 模块翻车的原因。需要注意的是自动建表在生产初版上线时也有隐患自动补出来的表在索引和注释上可能不够规范。所以我建议生产环境用 Flowable 官方 SQL 目录里与当前引擎版本严格对应的 DDL 手动建一遍而不是依赖自动建表也不是去网上随便找一份“通用工作流建表语句”。2.2 初始化 SQL 中建表语句的字段拆解bpm_category、bpm_form、bpm_task_assignee_rule先看最基础的流程分类表初始化 SQL 里的建表语句大概率长这样CREATE TABLE IF NOT EXISTS bpm_category ( id bigint NOT NULL AUTO_INCREMENT COMMENT 分类编号, name varchar(30) NOT NULL COMMENT 分类名, code varchar(30) NOT NULL COMMENT 分类编码, creator varchar(64) DEFAULT COMMENT 创建者, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, updater varchar(64) DEFAULT COMMENT 更新者, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, deleted bit(1) NOT NULL DEFAULT b0 COMMENT 是否删除, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT100 DEFAULT CHARSETutf8mb4 COMMENTBPM 流程分类表;这里几个字段值得说清楚。id用bigint是为了容纳雪花 ID 这类分布式 ID 方案AUTO_INCREMENT只是 MySQL 侧的兜底deleted用bit(1)配合逻辑删除这是芋道框架的惯例查询层会统一追加deleted 0条件。create_time和update_time都给了 MySQL 侧的默认值这是为了让不走应用层 ORM 的脚本也能写出合法的时间。如果你拿到的脚本里没有IF NOT EXISTS那重复执行脚本时会在建表这一步直接报错这是判断脚本是否能安全重放的重要信号。第二张要关注的是动态表单表BPM 的表单配置是动态化的字段通常包括表单名、状态、表单类型和表单配置 JSONCREATE TABLE IF NOT EXISTS bpm_form ( id bigint NOT NULL AUTO_INCREMENT COMMENT 表单编号, name varchar(30) NOT NULL COMMENT 表单名, status tinyint NOT NULL COMMENT 表单状态1开启 0关闭, form_type tinyint NOT NULL COMMENT 表单类型10系统表单 20自定义表单, form_conf text COMMENT 表单配置JSON, remark varchar(500) DEFAULT NULL COMMENT 备注, creator varchar(64) DEFAULT , create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, updater varchar(64) DEFAULT , update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted bit(1) NOT NULL DEFAULT b0, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT100 DEFAULT CHARSETutf8mb4 COMMENTBPM 动态表单表;form_type的取值决定前端用哪种方式渲染表单10 表示系统内置表单20 表示自定义表单。form_conf存 JSON这块是业务上最容易改出问题的地方。初始化 SQL 里通常只插一条演示配置真正要对接业务时表单配置一般是后台页面生成到这张表里的SQL 文件和它关系不大。第三张是任务分配规则表这张表在初始化 SQL 里最容易忽略CREATE TABLE IF NOT EXISTS bpm_task_assignee_rule ( id bigint NOT NULL AUTO_INCREMENT COMMENT 规则编号, process_definition_id varchar(64) NOT NULL COMMENT 流程定义的编号, task_definition_key varchar(64) NOT NULL COMMENT 任务节点编号, type tinyint NOT NULL COMMENT 规则类型, options varchar(1024) DEFAULT NULL COMMENT 规则参数, creator varchar(64) DEFAULT , create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, updater varchar(64) DEFAULT , update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted bit(1) NOT NULL DEFAULT b0, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT100 DEFAULT CHARSETutf8mb4 COMMENTBPM 任务分配规则表;type决定这个任务节点交给人审批、角色审批、部门负责人审批还是发起人自己审批options里存对应的 JSON 参数。初始化 SQL 只保证这张表存在不一定会给每个流程节点都配上规则。我遇到过的典型情况是流程定义发布成功表单也挂好了但没人给第一个审批节点配置分配规则提交申请后流程卡在第一个节点不动后台看任务列表是空的查了半天才发现bpm_task_assignee_rule里根本没有对应记录。所以导入完初始化 SQL 后一定要确认分配规则表里有对应流程的数据或者准备好走后台界面去配置。2.3 初始化 SQL 中的“数据”部分菜单、字典、分配规则与演示 OA 数据建表语句只是初始化 SQL 的一半另外一半是种子数据。这部分通常包含四类内容每一类漏了都有独立症状。第一类是系统菜单往系统菜单表里插入 BPM 模块的目录、菜单、按钮权限让你登录后台后能看到“工作流”“流程管理”“表单管理”这些入口。第二类是数据字典比如流程实例状态、审批结果、请假类型这类数据不进字典表前端下拉框就是空的。第三类是任务分配规则给演示流程的节点预设审批人。第四类是演示业务数据芋道一般会带一个请假审批的演示模块配套bpm_oa_leave和bpm_oa_leave_apply两张表数据铺好以后你可以不发任何业务代码就跑通一次完整审批。字典数据的长相就是这个样子INSERT INTO system_dict_data (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 进行中, 1, bpm_process_instance_status, 0, primary, primary, NULL, 1, NOW(), 1, NOW(), b0), (2, 已结束, 2, bpm_process_instance_status, 0, success, success, NULL, 1, NOW(), 1, NOW(), b0);注意dict_type必须和后端枚举类的命名对齐value必须和枚举数值一致否则界面上会出现“标签有值、后端不认”的错位。这类问题日志里不会报错只能通过界面现象反推。演示数据的价值在于初始化完成后不需要先写业务表就能在后台发起一个请假申请走完提交、审批、通过整个链路这给我当初验证环境是否真的配好省了大量时间。生产环境接真实业务时演示表可以留着当测试数据也可以删掉看团队习惯。3. 在 MySQL 上执行 BPM 初始化 SQL从环境检查到导入验证上一章说的是脚本内容这一章直接落到命令和参数。准备工作不需要重装 MySQL但需要先确认几个关键参数导入命令分两种场景选一种导入之后再过一遍验证清单这样才算真正把初始化 SQL 变成可用的数据库基线。3.1 导入前需要确认的 MySQL 参数字符集、时区、大小写、sql_mode先连上 MySQL跑一组状态查询SHOW VARIABLES LIKE character_set_server; SHOW VARIABLES LIKE collation_server; SELECT global.time_zone, session.time_zone; SELECT sql_mode; SELECT lower_case_table_names;逐个解释参数取舍。character_set_server建议是utf8mb4。芋道 BPM 的菜单名、流程分类名都是中文演示数据里可能还有 emojiutf8mb4是唯一不会出问题的方案。如果当前服务器变量是latin1不要直接导入先建一个指定字符集的库再用这个库执行脚本常见做法是CREATE DATABASE yudao_bpm DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;time_zone与初始化 SQL 的关系弱一些但与项目启动后的关联强。MySQL 里timestamp字段受时区影响datetime不受影响。芋道框架基类字段用的是datetime所以初始化 SQL 本身问题不大但如果你 Java 服务时区是GMT8写代码时又用了timestamp字段时间差 8 小时的问题就会冒出来。建议 JDBC URL 上显式带serverTimezoneAsia/Shanghai同时 MySQL 全局时区也设置为Asia/Shanghai。sql_mode是导入前必须确认的。ONLY_FULL_GROUP_BY会影响 BPM 运行期的统计查询不假但初始化 SQL 阶段影响最大的是NO_ZERO_DATE和NO_ZERO_IN_DATE。如果你的 SQL 脚本里有0000-00-00 00:00:00这种历史遗留默认值在这个模式下直接报错。另一个常见的坑是lower_case_table_namesMySQL 5.7 和 8.0 行为差异很大尤其 Docker 容器里的 MySQL 8 挂载旧数据目录时经常出现参数不一致导致启动失败。对初始化 SQL 来说表名统一小写最省心。参数确认完以后还有一件事容易被忽略连接 BPM 应用的数据源账号权限。初始化 SQL 里有建表语句账号至少要有CREATE、INSERT、ALTER权限。很多人在公司库上遇到导入报错不是 SQL 有问题而是账号只有 DML 权限、没有 DDL 权限。3.2 一条命令导入与交互式 source 导入哪种环境适合哪种做法服务端手动导入最直接的方式是命令行重定向mysql -h127.0.0.1 -uroot -p --default-character-setutf8mb4 yudao_bpm /home/user/sql/bpm.sql参数说明-h指定连接地址本地环境可以用127.0.0.1容器部署要换成容器 IP--default-character-setutf8mb4主要作用是让客户端的连接字符集确定下来避免不乱码最后的yudao_bpm是目标库名脚本里的表都建到这个库里。如果你是在服务器上操作脚本路径务必写绝对路径避免source相对路径带来的玄学问题。本地调试还可以用 MySQL 命令行交互式导入USE yudao_bpm; SET NAMES utf8mb4; SOURCE /home/user/sql/bpm.sql;SOURCE是 MySQL 客户端内建命令会把文件当作标准输入逐条执行优点是一行报错后面继续跑方便你定位是哪一条语句出了问题。如果你用的图形化客户端注意脚本里包了DELIMITER存储过程的情况这类语句在图形界面直接执行会卡住命令行反倒最可靠。导入顺序本身没有太多依赖因为芋道这套设计基本不用数据库外键表与表之间的关联靠应用层维护。但有一个保险动作我建议做导入前确认外键检查关闭。可以在命令行给数据库设置会话变量再导入mysql -h127.0.0.1 -uroot -p --default-character-setutf8mb4 \ -e SET FOREIGN_KEY_CHECKS0; SOURCE /home/user/sql/bpm.sql;这条命令把FOREIGN_KEY_CHECKS在当前会话关掉防止脚本里某些历史遗留的建表顺序问题导致外键引用失败实际使用时如果脚本内部已有这个变量设置重复执行也不影响。3.3 导入后的验证清单表数量、种子数据、常用表内容导入结束之后先不要急着启动应用用三分钟做一遍验证能省下后面半小时排错。SHOW TABLES LIKE bpm%; SELECT COUNT(*) FROM information_schema.tables WHERE table_schema yudao_bpm AND table_name LIKE bpm_%;第一条看表名列表第二条统计bpm_表的数量。具体数量跟你拿到的分支有关通常在 7 到 10 张之间。如果一张都没有多半是脚本没执行成功前面某条语句卡住或者被图形客户端拦住了。再查种子数据SELECT id, name, code, deleted FROM bpm_category; SELECT id, name, status, form_type FROM bpm_form; SELECT id, type, status FROM bpm_oa_leave LIMIT 5; SELECT dict_type, COUNT(*) FROM system_dict_data GROUP BY dict_type;bpm_category和bpm_form至少各有一条初始化数据字典表里应该能看到bpm_process_instance_status这类分组。如果dict_type分组结果里没有 BPM 相关字典说明脚本的 DML 部分被提前跳过需要把脚本里 INSERT 字典的部分单独执行。最后是启动验证这一步才真正把数据库和程序串起来。启动时观察日志里是否有 Flowable 自动建表的迹象启动完成后登录后台确认菜单里能看到工作流入口然后发起一次演示请假流程走到审批节点确认任务能正常分配出去。这一套流程走通初始化 SQL 才算真正完成任务。4. BPM 工作流初始化 SQL 在 MySQL 下的避坑排查5 个真实场景这里写的每个问题都来自实际部署中反复出现的情况每条按“现象 → 原因 → 解决”展开你导入时遇到可以直接对照。4.1 现象Flowable 引擎表没有生成或者一启动就报 ACT_GE_PROPERTY 不存在现象是应用启动到一半日志里抛出Table yudao_bpm.ACT_GE_PROPERTY doesnt exist或者报 Flowable schema 版本错误。原因不是初始化 SQL 没导好而是引擎自动建表策略没生效。BPM 初始化 SQL 本来就不包含ACT_表这批表依赖 Flowable 的 schema 管理。当配置里关闭了自动建表或者数据源没有正确交给流程引擎时引擎表就缺了。解决分两步第一步查配置把引擎建表策略临时调整为自动更新模式让 Flowable 启动时补齐缺表第二步是如果你所在团队要求生产环境把表手动建到位不要拿网上随便一份ACT_建表语句来跑必须用与当前 pom 里 Flowable 版本严格对应的官方 DDL。我见过太多次因为图省事导入旧版本引擎表最后被版本不匹配折磨的经历。4.2 现象表建好了但中文全部变成问号现象是导入后查询bpm_category中文分类名显示成????或者后台界面上流程分类名乱码。原因十有八九不是 SQL 文件本身的问题而是导入时客户端连接字符集不对。Linux 服务器的默认 locale 可能是 POSIX命令行执行 mysql 时不加字符集参数客户端就会按 latin1 把 UTF-8 字节流解释一遍再写进表。解决方法是导入命令加上--default-character-setutf8mb4或者在交互式命令行先执行SET NAMES utf8mb4再SOURCE。建库时也要把库和表的默认字符集定死在utf8mb4。如果已经导完才发现乱码不要直接在原表上改字符集正确做法是重新建一个字符集正确的库重新导入一次。4.3 现象执行初始化 SQL 时报 “Invalid default value for create_time” 或 ERROR 1067现象是脚本建表阶段跑得好好的执行到某一张表时突然中断报ERROR 1067 (42000): Invalid default value for create_time。原因是 MySQL 的sql_mode包含了NO_ZERO_DATE或NO_ZERO_IN_DATE而脚本里某个字段默认值写了0000-00-00 00:00:00。这类写法在早期版本的习惯里很常见新版本严格模式下不再接受。解决方式是在当前会话调整sql_modeSET SESSION sql_mode STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION;这条命令去掉了NO_ZERO_DATE和NO_ZERO_IN_DATE导入完成后再恢复原值。如果脚本是你自己团队维护的顺手把零值改成CURRENT_TIMESTAMP更省事。需要注意的是这个报错跟慢 SQL 优化没有关系不要往索引和执行计划上查看到 ERROR 1067 就直接想到严格模式。4.4 现象初始化后登录后台管理员看不到流程分类和表单数据现象是数据库里bpm_category有记录后台界面列表却是空的查接口也没返回数据。原因是芋道是典型的多租户架构业务表基本都有tenant_id列数据权限过滤依赖这个字段。初始化 SQL 里的种子数据如果tenant_id为空或者写的是某个默认租户而登录用的管理员不在这个租户下查询结果自然被过滤掉。解决方式有两种。推荐的做法是直接走后台界面把流程分类、表单、分配规则手工维护一遍让系统自动写入正确的租户 ID。如果数据量比较大需要用 SQL 批量修正先确认当前租户的 ID然后执行UPDATE bpm_category SET tenant_id 1 WHERE tenant_id IS NULL;1换成实际租户 ID。不要觉得“表里有数据就万事大吉”多租户下数据可见性本身就是一层很强逻辑初始化脚本不会替你把每个租户都铺一遍数据。4.5 现象重复执行初始化脚本导致菜单、字典数据重复甚至 ID 冲突现象是初始化脚本跑了两遍后台菜单多了一倍字典表里同一个dict_type出现多条相同记录。原因是初始化 SQL 里 DDL 部分有IF NOT EXISTS保护DML 部分却没有幂等处理直接INSERT永远插新值又没有唯一索引兜底。解决方式是执行前先摸底不要盲目重放SELECT dict_type, value, COUNT(*) FROM system_dict_data WHERE dict_type LIKE bpm_% GROUP BY dict_type, value;如果已经有数据要么跳过 DML 部分要么先删后插。非要让脚本可重放可以把 INSERT 改成带清理的写法DELETE FROM system_dict_data WHERE dict_type bpm_process_instance_status; INSERT INTO system_dict_data ...;执行删除操作前确认你当前库里的数据不是后期手工维护过的避免把正常配置一起清掉。初始化脚本不是为反复执行设计的把它当成一次性基线和代码生成器的输入而不是日常 CI/CD 脚本。5. 让初始化 SQL 从“一次性部署”变成“流程初始化模板”初始化 SQL 跑通以后下一步通常是把它改造成自己团队的流程初始化模板。这里有一个很实用的切入点不要直接去改建表语句而是把 DML 部分抽出来做成自己的流程分类初始化脚本。5.1 用一条 INSERT 建立自己的流程分类业务方告诉你“下个月要上线一个订单审批流程”你不需要重新建库建表只需要往分类表里补一行INSERT INTO bpm_category (name, code, creator, create_time, updater, update_time, deleted) VALUES (订单审批, order_approval, 1, NOW(), 1, NOW(), b0);name是界面展示名code是编码后续在 BPMN 文件里绑定流程分类时前端拿 code 做匹配。这一条语句就是最小可行的流程初始化手段比在界面上点半天更快也比直接改全量初始化 SQL 更安全。新增的流程分类表发布流程定义挂在它下面即可。5.2 初始化后再做一次“最小流程验证”分类建好之后我建议固定走一遍这套验证动作。第一步启动后端服务看日志里 Flowable 自动建表和 schema 校验没有异常第二步登录后台确认菜单、分类、字典都在第三步设计一个只有两个节点的极简 BPMN发起人提交组长审批发布后走一遍完整链路。这一步发现问题是最便宜的。流程卡在某个节点时优先查bpm_task_assignee_rule有没有对应节点的分配规则这条路径上踩的坑比流程图本身多得多。验证通过以后再把这个分类下的真实流程一个个迁过来迁移成本会低很多。5.3 我在团队里围绕初始化 SQL 形成的工作习惯做这类初始化工作时我自己的习惯是“先盘后导导完验核验完留档”。先盘是看脚本里有没有IF NOT EXISTS、有没有DELIMITER、有没有tenant_id然后决定怎么导导完验核是用SHOW TABLES和几条SELECT确认表和种子数据都到位最后把初始化 SQL 文件按日期存档和对应的应用版本绑定避免以后再部署时拿到一份和代码不匹配的旧脚本。这也是我从几次翻车里总结出来的固定流程第一次拿旧脚本配新代码启动全是 ACT_ 表版本冲突第二次没加字符集参数界面全是乱码第三次忘了租户字段列表空白。后来把这三步固定成检查清单再没出过事。希望帮到你。本文还有配套的精品资源点击获取