达梦 DM8 + openGauss:RuoYi Office 的 MySQL 数据转换与导入实践
🌐 文档地址 :https://ruoyioffice.com
👇 文章底部获取源码和演示地址 👇
💬 :17156169080(获取产品咨询)
企业管理系统迁入国产数据库,迁移对象除了表结构,还有组织权限、业务主键、流程定义和二进制资源。本文以 RuoYi Office 的包装转换流水线为例,讲清怎样把 MySQL 基线变成可审核、可导入、可验证的达梦与 openGauss 数据包。

▲ 源数据包经过转换和校验,再分别进入达梦 JDBC 与 openGauss gsql 导入路径;流水线同时保留来源、警告与对象统计。
引言:SQL 转完了,为什么流程却发不起来?
SQL 转换成功,首先说明工具产出了目标文本。它并不自动证明所有表都存在、所有数据都保留、运
行时查询都兼容。
企业管理平台尤其依赖"结构 + 初始化资料 + 配置 + 流程资源"的配套。用户记录导入了,但菜单
缺失,登录后仍可能无入口;模型导入了,但部署记录丢失,仍然没有可发起定义。
还有一种更隐蔽的失配:历史 ID 全部导入成功,序列却从较小值开始,第一次新增就出现冲突。
| 表面现象 | 真正可能缺失的资产 | 应验证的产品动作 |
|---|---|---|
| 表结构完整 | 角色、菜单、字典 | 登录并打开业务入口 |
| 模型列表有内容 | 部署与流程定义 | 检查可发起流程 |
| 流程图能显示 | 可写主键与运行表 | 新增或发布 |
| 历史数据能查询 | 主键序列校准 | 插入新记录 |
| SQL 执行无报错 | 长文本或二进制完整性 | 解析流程资源 |
因此迁移工作要以"数据包能解释,产品路径能验证"为目标,而非只把语法换成另一种数据库能接受
的形式。
一、从迁移后的产品入口反推数据责任
1. 登录与工作台依赖基础资料

▲ 既有开发环境真实工作台,用于说明初始化资料的产品影响;图中数据库不是本文目标库实测证据。
用户、组织、角色、菜单和字典属于产品运行所需资产。哪些数据放入初始化包,应由产品和交付规
则明确,不能在转换器里临时猜测"这张表大概不重要"。
某些业务表包含演示数据,是否迁移也需要区分初始化交付与客户历史数据迁移。本文采用的历史实
验基线,不等于任何客户生产数据库的全量备份。
2. 可发起流程依赖发布资产

▲ 本地真实流程入口,帮助核对数据迁移后应该出现的能力;入口展示需要结合目标库定义与权限检查。
模型、发布批次、可执行定义和资源内容需要保持配套。只统计设计模型,会遗漏运行资产的完整性
。
3. 业务详情检查字段与关联

▲ 本地开发环境真实单据,展示中文、时间、印章资料与审批身份。它是页面检查示例,不冒充迁移后的目标库单据。
迁移验收应让结构核对与产品行为互相支持。SQL 能看到中文,不代表日期 JSON 契约正确;单据能
打开,不代表新 ID 可以生成。
二、统一入口为什么比直接运行转换器更可靠
RuoYi Office 保留基础转换器原样,通过包装层处理项目已发现的问题。入口位于数据库仓库,实
际转换实现位于交付工程。
这样既能复用基础转换能力,也能把项目补充规则、审核记录和失败门禁保留下来。
1. 明确三个输入和一组版本关系
核心输入是 MySQL schema、static_data 和基础转换器;还需要目标库专用 Quartz 脚本等配套资
产。
| 输入或资产 | 责任 | 缺失的后果 |
|---|---|---|
| schema | 源表结构与类型 | 字段语义无法恢复 |
| static_data | 资料、配置与流程数据 | 空库不能支撑产品入口 |
| 转换器 | 基础目标语法转换 | 目标文本无法生成 |
| 包装规则 | 项目特定补充处理 | 已知问题重复发生 |
| 专用 Quartz SQL | 任务持久化表 | 应用调度组件启动失败 |
| 运行时应用版本 | 实际读取与写入契约 | 数据库基线落后于代码 |
历史实验使用 2026 年 8 月 31 日的 schema 与 static_data,覆盖 782 张源表。后续应用新增字
段,需要配套目标库增量,不能仅修改应用版本号。
2. 入口先检查路径,再生成并验证清单
以下是现有 PowerShell 入口的核心摘录。它把输入显式传入生成器,再执行 manifest 检查;两个
阶段出现非零退出码都会终止。
powershell
foreach ($Path in @($Schema, $Data, $Converter, $UpstreamSql, $Generator, $Adapter)) {
if (-not (Test-Path -LiteralPath $Path)) { throw "Required path not found: $Path" }
}
& $Python $Generator `
--schema $Schema `
--data $Data `
--converter $Converter `
--adapter $Adapter `
--upstream-sql $UpstreamSql `
--output $Output `
--python $Python `
--targets $Targets
if ($LASTEXITCODE -ne 0) { throw "信创 SQL generation failed with exit code $LASTEXITCODE" }
& $Python (Join-Path $PSScriptRoot 'verify_manifest.py') (Join-Path $Output 'manifest.json')
if ($LASTEXITCODE -ne 0) { throw "manifest verification failed with exit code $LASTEXITCODE" }
命令参数使每次转换可以指向明确基线,不依赖"latest 目录里现在恰好是什么"。目标数据库列表
也记录在生成资产中。
现场复用时,应采用自己的固定路径和输出目录,保留原基线与转换结果。本文不执行任何数据库导
入或覆盖客户数据。
三、转换器做语法处理,包装层保留业务语义
1. 先把完整 INSERT 交给转换器
MySQL Dump 可能把一个 INSERT 的字段与多行 VALUES 分开放置。转换器若按物理行解析,容易漏
数据或误读字段。
包装层首先识别完整语句,再合并为可解析形式,同时支持带字段列表的 INSERT。判断完整语句时
需要考虑字符串与转义,不能把任意行尾分号都理解为整条语句结束。
但合并成功并不解决目标导入工具的长度约束。语句解析和目标执行是两项独立责任。
2. 清理规则必须只作用于目标语法
历史问题中,宽泛的 ENGINE.* 清理规则把 Flowable 数据中的 ENGINE_VERSION_ 一并截断,
导致部署与定义数据静默丢失。
当前规则限定到建表选项行。下面摘取相关处理,说明修复发生在输入清理层,不是在运行时查询中
补造部署数据。
python
# Only rewrite CREATE TABLE option lines. The upstream ENGINE.* patterns
# also matched Flowable's ENGINE_VERSION_ INSERT column and truncated
# ACT_RE_DEPLOYMENT / ACT_RE_PROCDEF data silently.
content = re.sub(
r"(?im)^(\)\s*)ENGINE[^;\r\n]*COMMENT", r"\1COMMENT", content
)
content = re.sub(
r"(?im)^(\)\s*)ENGINE[^;\r\n]*;", r"\1;", content
)
# Upstream splits CREATE TABLE on the first ';'. Keep comment text
# from truncating Jimu / similar tables.
content = re.sub(
r"COMMENT\s+'([^']*)'",
lambda match: "COMMENT '" + match.group(1).replace(";", ";") + "'",
content,
)
这条原则可以推广到其他迁移:文本替换必须知道自己在处理 DDL 选项、字段、字符串还是业务数
据,不能靠相同前缀推断含义。
3. 类型映射不能丢掉原始语义
BIT(1)、长文本、时间、二进制和字符串主键,都需要关注源语义。看到 id 列,不代表它一定
是整数自增;看到 0 / 1,不代表该字段一定应该转为目标布尔类型。
PostgreSQL 对照适配中,普通位值先采用整数导入,Flowable 的指定标志列再转换为引擎要求的 b
oolean。这个结果说明,应区分业务字段与引擎字段,不能一刀切。
| 转换对象 | 当前处理方向 | 仍需核对 |
|---|---|---|
| 整数主键 | 达梦 IDENTITY / PG 类序列 | 新 ID 不与历史值冲突 |
| 文本主键 | 保留文本身份 | 长度、唯一性与大小写 |
| 中文字段 | 保留字符语义 | 编码、长度与排序 |
| BIT 字面量 | 归一化再按目标要求处理 | 是否应为整数或布尔 |
| BLOB / bytea | 目标表达式或绑定参数 | 内容长度与解析结果 |
| 日期时间 | 目标类型与应用契约配对 | 精度、空值、序列化 |
金额精度与比较规则也属于数据语义
金额字段应核对精度和小数位,不能只看到目标列仍是 DECIMAL 就结束检查。
对于字符串,还应关注大小写、空格与比较规则对查询和唯一约束的影响。
目标库接受一条记录,不等于它与其他记录之间的业务关系保持不变。
这些检查应使用代表值和实际业务规则,不通过批量清洗历史数据来掩盖差异。
4. 遗漏表兜底需要带着限制交付
基础转换器不能直接处理的六张 ERP 表,包装层提供了有限兜底。兜底解决"产物没有这张表",不
代表该表所有普通索引、复杂默认值和注释已与源库完全一致。
因此兜底表必须进入审核清单。实施人员应检查表结构、主键、唯一约束、普通索引和默认值,再通
过目标模块的实际写入验证。
对业务影响大的表,索引差异即使不影响小数据量功能,也可能影响后续查询性能。功能验收和容量
验证需要分别安排。
四、让流程资源丢失在转换阶段就失败
1. 检查源中存在的关键 INSERT
当前生成器核对四类 Flowable 仓库表:模型、部署、定义和二进制资源。如果源数据有 INSERT、
目标产物却没有,会抛出异常。
python
def validate_flowable_repository_data(source_data: str, converted: str, db_type: str) -> None:
required = {
"act_ge_bytearray",
"act_re_deployment",
"act_re_model",
"act_re_procdef",
}
source_tables = insert_tables(source_data)
target_tables = insert_tables(converted)
missing = sorted((required & source_tables) - target_tables)
if missing:
raise RuntimeError(
f"{db_type} conversion lost Flowable repository INSERT data: "
+ ", ".join(missing)
)
这个门禁判断的是"表级 INSERT 是否保留",并非逐行哈希一致,也没有证明每个资源都可解析。后
续实库检查仍需继续。
把门禁能力说清楚,比把它称作"全量数据一致性校验"更准确。
2. 为产物建立可追溯关系

▲ 迁移交付的逻辑模型,表达源基线、规则版本、目标包与验收记录的关系;这些对象并非平台已新增的数据库业务表。
| 记录字段 | 当前用途 | 不能替代的检查 |
|---|---|---|
| 源文件 SHA-256 | 固定输入身份 | 源数据本身正确性 |
| 转换器 SHA-256 | 固定工具来源 | 规则对业务的适用性 |
| 目标 SHA-256 | 固定产物内容 | 目标库导入成功 |
| warning 与兜底表 | 提示人工审核范围 | 结构与功能回归 |
| 对象统计 | 发现遗漏或计数变化 | 行数和内容逐项比对 |
| known_limitations | 保存交付边界 | 客户实际验收 |
当前 manifest 记录基础转换器身份和额外处理规则。进一步提高复建能力时,建议同时归档包装层
源码版本或校验值;不能把现有记录描述成已自动计算每一份代码的哈希。
五、达梦与 openGauss 使用不同导入路径
1. 达梦用 JDBC 承载长语句与二进制
达梦权威导入采用官方 JDBC 逐条执行。二进制表达式会被解析成字节数组,转换为绑定参数后调用
setBytes。
这样可以避免把命令行物理行长度限制带入流程资源导入。导入器还区分函数定义与普通语句的结束
方式。
不过当前实现存在分批提交,已经提交的前序批次不会因后面的异常自动消失。失败后必须检查库状
态,不应假设全量导入具有一个原子事务。
2. openGauss 用 gsql 严格处理执行错误
openGauss 采用 gsql --set ON_ERROR_STOP=on,以避免发生错误后继续执行后续语句。这里的"
严格"指错误终止,不代表所有 DDL 与数据自动整体回滚。
导入后核对 schema、表、中文、流程定义和序列,再启动匹配 Profile。不要反过来依赖应用自动
建表补齐初始化缺失。
| 导入阶段 | 达梦 | openGauss |
|---|---|---|
| 运行时 | 官方 DM JDBC | gsql |
| 二进制 | 字节绑定与目标表达式 | bytea / decode 路径 |
| 历史整数 ID | IDENTITY_INSERT | 显式 ID + 序列校准 |
| 错误处理 | 异常终止并保留位置 | ON_ERROR_STOP |
| 产品验证 | 用印审批闭环已有证据 | 登录、发布、填报已有证据 |
3. 按时序完成数据到产品的交付

▲ 转换门禁、目标导入与产品验收是三个依次衔接的阶段;前一阶段通过,不替代后一阶段。
六、实库验证为什么不能只比较表数
782 与 783 的差异,在本实验中来自兼容表 dual,不是自动表示缺表或多迁移了一份业务数据。
反过来,即使表数一致,也可能缺索引、默认值或某个流程定义的数据。应按对象类别和代表业务分
层验证。
| 检查层 | 示例 | 通过条件 |
|---|---|---|
| 结构 | 业务表、Quartz 表、字段类型 | 与目标包设计一致 |
| 资料 | 用户、字典、印章中文 | 指定基线完整 |
| 引擎资产 | 模型、部署、定义、资源 | 关联存在且可用 |
| 新数据 | 取号、保存、发布 | 主键策略正确 |
| 应用读写 | 登录、表单、流程任务 | 实际业务语义保持 |
| 异常路径 | 拒绝、启动失败、恢复 | 状态和恢复方法明确 |
建议将这些结果写成可复用验收清单,并记录使用的目标库版本。后续刷新 MySQL 基线时,可以重
跑同一套检查,而不是重新发明验收步骤。
七、迁移之后怎样持续升级
初始化迁移是起点,客户后续升级还会收到新增字段、索引和业务数据变更。MySQL 增量不能被默认
视为达梦或 openGauss 可直接执行的增量。
应先确定客户当前基线,转换或编写目标方言的配套升级资产,保留已交付脚本不变,并新增纠错与
升级版本。
已有业务数据的客户还需要明确停写窗口、备份、恢复点和变更顺序。本文实验初始化路径不能直接
变成一个覆盖生产数据的迁移指令。
回滚也要回答应用包、schema 与数据是否能够配套恢复。只回退应用文件,无法自动恢复数据库结
构和新增业务事实。
当一份目标包导入失败:怎样判断重建、补偿还是继续
假设达梦导入在某个长资源语句失败,前面已有几批数据提交。
这时不应立即重复运行全部文件,先固定失败位置和目标库状态。
保留失败语句对应的业务对象
记录脚本文件、语句位置、目标表与数据库错误。
再从源资产确认它是普通业务记录、结构定义,还是流程资源。
日志展示语句时,注意其中可能带业务信息或敏感内容;交付报告保留可定位身份即可。
若是流程二进制,继续检查字节长度、源表达式与目标绑定方式。
若是普通文本,检查编码、长度语义和转义,不先修改通用数据库驱动。
先确认已提交范围
分批提交意味着错误发生前的部分数据可能已经落库。
检查目标表与导入计数,再决定是否在干净测试库重新生成和导入。
不能把事务异常理解成所有 DDL 与历史批次都已回滚。
如果选择继续导入,必须明确语句幂等性和已经执行的结构,不盲目跳过所有重复键错误。
当前达梦导入器只对已确认等价索引的特定情况容错,不是一个"任何报错都跳过"的工具。
回查源资产,不在目标库里临时捂数据
错误类型应回到源 DDL 与转换规则核对。
流程资源缺失应回到清理和 INSERT 解析层。
序列不匹配应回到导入后的校准步骤。
若只在目标库手工补一份数据,下次重新生成仍会重复发生,交付资产也无法解释现场状态。
明确根因后,生成新版本产物并保留旧版本身份,才具备复建能力。
| 失败类型 | 推荐处理 | 需要留下的证据 |
|---|---|---|
| 类型无法转换 | 对照源 DDL 修正规则 | 类型语义与新产物身份 |
| 定义 INSERT 缺失 | 限定清理范围与资源门禁 | 源 / 目标关键 INSERT |
| 二进制执行失败 | 核对长度与绑定 | 资源身份和内容验证 |
| 主键冲突 | 核对显式 ID 与序列 | MAX、序列与实际取号 |
| 普通索引缺失 | 核对目标结构与查询 | 索引比对与业务用例 |
| 应用字段缺失 | 配套目标库增量 | 应用与数据基线关系 |
不同批次的 manifest 不能互相冒名
统一入口支持多个目标,但某次运行可能只生成一个目标。
例如后续清单记录 targets=postgres,只能作为这次 PostgreSQL 产物的审计依据,不能证明此
前达梦与 openGauss 产物同样来自这个基线。
实验室最初的 782 张源表,和后续基线的对象统计也可能发生变化。
所以客户收到每个目标包时,都应找到它自己的源身份、目标身份和生成记录。
"仓库里有三套 SQL"与"三套 SQL 属于同一批输入"不是一个结论。
警告应当怎样关闭
将警告按表和语义分类,再决定由规则处理还是人工审核。
复杂默认值与普通索引可以逐项核对;无法恢复的业务语义应保留未解决状态。
不能通过删除 warning 文件,让交付清单变成零警告。
关闭一项警告至少应说明原问题、处理方式和新验证结果。
新基线要覆盖哪些回归
刷新初始化资产后,重跑对象核对、登录、发布和代表写入。
再对新增模块或变更字段补测试,不必机械重做所有无关页面。
如果更换了转换器或驱动,则应扩大到对应受影响的语法、认证和写入路径。
| 变化 | 回归重点 |
|---|---|
| 数据基线刷新 | 新字段、资料、流程资源 |
| 转换器变化 | 类型、INSERT、结构与门禁 |
| 驱动变化 | 认证、依赖与批量写入 |
| 应用升级 | 运行时 SQL 与业务状态 |
| 目标库升级 | 语法、系统视图与功能行为 |
让回归范围跟随实际变化,能同时提高效率和证据质量。
清单验证还要与实际文件核对
当前 verify_manifest.py 检查版本、必备处理记录、目标哈希字段、警告引用与兜底记录等。
它不是一套会自动重算所有文件内容、并证明目标库数据一致的审计系统。
实施人员应理解检查器的实际能力,而不是只把 manifest OK 写进报告。
尤其在 SQL 被拷贝、修改或重新压缩后,需要核对最终交付文件与清单身份。
| 检查 | 当前用途 | 交付补充 |
|---|---|---|
| 哈希字段存在 | 清单记录完整 | 对实际文件重算与比对 |
| 警告有引用 | 人工审核可定位 | 阅读并关闭对应问题 |
| 关键 INSERT 记录 | 避免表级资源静默丢失 | 检查行数与内容可解析 |
| 目标列表 | 确认本次生成范围 | 分别关联每个交付包 |
清单、文件和实库结果是三类相互支持的证据。
清单证明来源声明,文件核对证明收到的内容,实库验证证明内容能够被应用使用。
这三项对应完成后,才适合把迁移结果交给下一位实施人员复用。
八、快速体验
在线演示:https://ruoyioffice.com/web/
使用 admin / admin123 查看工作台、发起入口和用印详情,理解迁移资产最终支撑什么产品能力
。
实际转换入口是数据库仓库 tools/xinchuang/generate.ps1。调用时显式传入 schema、static_d
ata、基础转换器、专用 SQL 路径和输出目录;先生成与审核,再导入获准的目标环境。
常见问题(FAQ)
SQL 转换成功,是否可以直接上线?
还需审核产物、实库导入、对象核对和应用回归。当前工具已有完整性门禁,但不代替运行时 SQL
与业务验证。
达梦为什么优先采用 JDBC 导入?
流程资源包含长文本和二进制。现有 JDBC 导入器能按完整语句执行,并对二进制使用绑定参数,避
免命令行长度成为隐含限制。
表数不同一定表示转换错误吗?
需要分析对象类别。实验中 PG 类目标多出的 dual 是兼容表;表数相同也不能独立证明字段、约束
和内容完全一致。
PostgreSQL 转换结果能直接证明人大金仓通过吗?
不能。它是兼容对照资产,人大金仓还需要指定版本、驱动、兼容模式与代表业务的实库验证。
结语:把迁移做成可以审查的流水线
国产数据库迁移的难点,是让源数据、转换规则、目标对象和应用行为一直保持同一种业务语义。
RuoYi Office 的包装层把已发现的问题固化为处理与门禁,把警告、来源和限制留在交付资产中。
实施人员因此能解释每一步做了什么,也能明确还要验证什么。
你们的迁移交付包里,除了目标 SQL,是否还包含源基线、工具身份、警告和代表业务验收记录?这
些资产决定了下一次升级能否顺利复用。
系列阅读
- openEuler + 毕昇 JDK + Tengine:RuoYi Office 国产化部署实战
- SpringBoot3 + 达梦 DM8:RuoYi Office 用印申请与多级审批实战
- SpringBoot3 + openGauss:RuoYi Office 登录、流程发布与用印填报适配实战
- 达梦 DM8、openGauss、人大金仓怎么选?RuoYi Office 国产数据库适配与验收指南
- openEuler + 达梦 DM8 + openGauss:RuoYi Office 多库部署与运行维护实践
如果这篇对你有用,点个「在看」或收藏。
🌐 演示地址 :https://ruoyioffice.com/web
📦 GitHub 源码 :https://github.com/yuqing2026/ruoyi-office
📦 Gitee 源码 :https://gitee.com/yqzy1688/ruoyi-office
💬 微信:17156169080(获取产品咨询)

打开演示地址直接查看系统。