首页 / 资讯中心 / 文章详情

MySQL到达梦数据库迁移全流程:结构改写、数据导入与验证

MySQL到达梦数据库迁移全流程:结构改写、数据导入与验证 ★ FEATURED ARTICLE
最近好几个项目的朋友都在跟我吐槽MySQL迁到达梦数据库的活儿看着简单真上手就各种报错网上教程东一榔头西一棒子很少有一条完整的链路。我自己前段时间刚完整做了一套MySQL到DM8的迁移从工具选型、数据导出、结构重建到数据导入、应用适配、线上验证一路踩坑踩过来最后整理出了一套能在三分钟内完成迁移的实操流程。这篇文章就把这套流程完整记录下来不管你是DBA还是后端开发只要正在做MySQL到达梦的迁移或者被各种兼容性问题折磨得头大照着做能少走不少弯路。1. 迁移方案选型先想清楚走哪条路在动手迁移之前别急着找工具先想清楚自己手上有哪几条路可以走。目前MySQL到达梦的迁移常见的有三条路线一是达梦自带的DTS数据迁移工具图形化界面从源端到目标端一键操作二是手工导出SQL脚本再导入步骤可控、链路透明三是借助第三方ETL工具比如DataX、Kettle适合有数据清洗和转换需求的场景。我实测下来三分钟内完成迁移这个目标用的其实是第一和第二条路线的组合mysqldump导出MySQL数据把结构脚本改写之后在达梦端重建表结构数据量大的表用dmfldr批量加载数据量小的表直接执行SQL脚本。为什么没有完全依赖DTS因为DTS虽然界面友好但在处理复杂对象、特殊类型映射和大量数据时需要预判很多坑一旦报错排查起来反而慢。把导出和导入拆开做每一步都透明可控这才是“快速完成”的前提。1.1 达梦自带工具DTS能做什么DTS全称Data Transformation Service随DM8安装包一起提供默认在达梦安装目录的tool子目录下。它的核心工作流是新建迁移作业、配置源端连接、配置目标端连接、选择迁移对象、执行迁移全程图形化操作对第一次接触达梦的人来说很友好。DTS连接MySQL时需要MySQL的JDBC驱动包如果本机没有这个jar包在配置源端连接时要手动指定路径这一步不熟悉Java环境的人容易卡住。另外DTS对常规的表、索引、数据行迁移处理得比较成熟但遇到存储过程、函数、触发器这类复杂对象它会尝试自动转换转换后的语法在达梦里很可能跑不通需要人工二次修复。还有一个经验是DTS默认配置下遇到目标表已存在、主键冲突、字段类型无法自动映射等情况会大量报错需要你逐条处理任务量大时很耽误时间。所以我对DTS的定位是小表数据搬迁、表结构简单、对象不复杂时DTS确实省事但如果是几十张甚至上百张表、带各种复杂对象的库反而不要过度依赖DTS拆开做更稳。1.2 手工导出导入在什么场景下最香手工方案听起来原始但在特定场景下是最稳的。先用mysqldump把MySQL侧的结构和数据导出成SQL文件然后改写脚本里的MySQL语法最后在达梦侧执行脚本完成数据加载。这样做的好处是链路上每一步都清楚出了问题能准确定位到是DDL、DML还是类型转换的问题而不是在一个黑盒工具里瞎猜。我这次项目里MySQL端大概有五十多张表其中十张大表数据量在百万行级别。用DTS迁了一半中途总是有一些表报主键冲突或类型转换错误排查起来非常费劲。后来切成“mysqldump导结构 拆分数据导出 达梦端批量导入”的组合方式速度反而提上去了。手工方案还有一个附加优势所有导出的脚本都是文本文件你可以全局替换、修改、注释掉某一段随时重跑这种掌控感在调试阶段特别重要。1.3 三种路线对比怎么选如果你还在犹豫用哪个方案我整理了一个简单对照对比项DTS工具手工导出导入第三方ETL易用性高图形界面中需要命令行基础中需要额外安装配置复杂对象支持一般需人工修复完全可控视工具而定大数据量性能一般需调批次参数配合dmfldr性能最好较好出错排查报错定位不够直观每步都有日志和文件可查依赖工具日志适合场景表少、结构简单表多、需要掌控迁移过程有数据清洗和转换需求选型没有绝对答案核心看你的场景。表少、结构规整用DTS最省时间表多、有复杂对象、需要反复调试手工方案更靠谱有异构系统数据整合需求上ETL工具更合理。2. 三分钟迁移的完整链路拆解标题说的三分钟不是指所有场景都是三分钟而是指一条已经跑通、没有坑的流程在中小体量数据库下可以做到三分钟内完成核心操作。这个时间包含从mysqldump导出到达梦数据导入完成不包含前面的方案设计和后面的应用改造先把这点说明白。如果你带着一个全新的库从零开始建议先花一小时把流程走一遍把坑排干净后面每次重复执行就是三分钟的事。2.1 导出阶段mysqldump的参数细节MySQL侧导出我用的是mysqldump。命令本身不复杂关键在于参数选择。先导出结构文件命令长这样mysqldump -u root -p --single-transaction --set-gtid-purgedOFF \ --databases yourdb --no-data yourdb_schema.sql再导出数据文件mysqldump -u root -p --single-transaction --set-gtid-purgedOFF \ --databases yourdb --no-create-info yourdb_data.sql这里几个参数都有讲究。--single-transaction在InnoDB引擎下能保证导出过程中不锁表线上导出不会阻塞业务写入这是必须加的。--set-gtid-purgedOFF也很关键MySQL开了GTID之后导出的文件默认会带上SET GLOBAL.GTID_PURGED...这种语句到达梦里根本无法识别执行就中断。--no-data和--no-create-info的作用是把结构和数据分成两个文件方便在达梦侧分别执行如果一个文件混着DDL和DML排错时不好定位。数据量大的表我建议单独导出不要把所有数据塞进一个超大SQL文件。比如一张300万行的表导出的SQL文件可能就有几个GB不管哪一步出错重跑一次都是折磨。按表导出可以做到单表维度控制进度某一张表失败了单独重跑这一张就行。2.2 结构改写从MySQL语法到达梦语法拿到yourdb_schema.sql之后直接在达梦工具里执行大概率会报错原因很简单MySQL和达梦的DDL语法有差异。我实际操作中主要改这么几类内容。AUTO_INCREMENT要改成IDENTITY(1,1)。MySQL建表时写id INT AUTO_INCREMENT PRIMARY KEY达梦等价写法是id INT IDENTITY(1,1) PRIMARY KEY。这里有个细节要提醒IDENTITY列在达梦中有使用限制不能随意往里面插入显式值。如果业务数据本身需要在导入时保留原有主键值建议不要用IDENTITY自增而是把主键列建成普通INT由业务程序自行生成主键这样导入时就不会遇到主键冲突。行尾定义直接删掉。MySQL建表语句结尾通常带ENGINEInnoDB DEFAULT CHARSETutf8mb4达梦没有这些概念保留反而报错。字段注释要改写。MySQL的列注释写在意建表定义里达梦最稳妥的是建表之后单独执行注释语句COMMENT ON TABLE 你的表名 IS 表的说明; COMMENT ON COLUMN 你的表名.列名 IS 列的说明;我的习惯是写一个小的文本处理脚本用正则表达式批量替换常见差异点比如把AUTO_INCREMENT替换成IDENTITY(1,1)把行尾定义删掉。替换完不要直接执行先检查一遍有没有漏网的MySQL专属语法确认无误后再在达梦端跑结构脚本。2.3 数据导入小表用脚本大表用dmfldr结构建好之后数据导入分两条路。数据量小的表直接执行数据SQL脚本就行disql SYSDBA/******localhost:5236 -f yourdb_data.sql注意disql是达梦的命令行客户端工具执行SQL文件时如果某条SQL报错默认会继续往下跑但后面依赖前面数据的SQL可能跟着失败所以导入后一定要做行数验证。数据量大的表我强烈推荐用dmfldr。dmfldr是达梦自带的批量加载程序用法和Oracle的sqlldr非常像核心是准备好控制文件.ctl和数据文件CSV。控制文件示例LOAD DATA INFILE /data/yourtable.csv INTO TABLE your_table FIELDS TERMINATED BY , OPTIONALLY ENCLOSED BY TRAILING NULLCOLS (col1, col2, col3, col4)CSV数据文件怎么来可以从MySQL端查询后输出也可以把mysqldump导出的数据转换格式。我更喜欢用脚本把查询结果直接写成CSV因为可以控制字段顺序、是否带表头和控制文件的列映射一一对应。执行导入命令dmfldr useridSYSDBA/******localhost:5236 control/data/dmfldr.ctldmfldr执行完会打印统计信息包括读取行数、处理行数、错误行数。如果错误行数不为0它会生成.bad后缀的错误数据文件你可以打开这个文件逐行看是哪些数据出了问题定位效率非常高。2.4 快速验证行数与抽样导入完成之后别急着收工先做一轮快速验证。最简单的是行数对比对每张表分别在MySQL和达梦执行SELECT COUNT(*)两边数字一致说明行数没问题。但行数一致不等于数据一致我还会抽几张关键表随机取几条记录看字段内容是否对应重点是中文字段、日期字段、金额字段。我一般是写一个对比查询脚本把两张表的抽样数据拼起来看人工过一遍心里就有底了。3. 类型映射与SQL方言差异最容易翻车的地方3.1 高频数据类型对照表迁移过程中最容易翻车的就是数据类型映射。MySQL和达梦的数据类型体系相似但不完全相同不能生搬硬套。我整理了一个高频对照表基本覆盖了90%以上的常规业务表字段。MySQL类型达梦类型说明TINYINTSMALLINT达梦没有TINYINT用SMALLINT范围足够SMALLINTSMALLINT直接对应INT/INTEGERINT直接对应BIGINTBIGINT直接对应DECIMAL(m,n)DECIMAL(m,n)精度保持注意不能超出达梦上限FLOAT/DOUBLEFLOAT/DOUBLE直接对应CHAR(n)CHAR(n)字符长度含义需要验证编码VARCHAR(n)VARCHAR(n)达梦按字符长度要确认字符集一致TEXTTEXT/CLOB建议用CLOB避免长度不足TINYTEXT/MEDIUMTEXT/LONGTEXTCLOB统一用CLOBBLOBBLOB直接对应DATEDATE直接对应DATETIMETIMESTAMP达梦TIMESTAMP语义接近DATETIMETIMESTAMPTIMESTAMP注意默认值表达式差异BIT(1)BIT长度语义要核对JSONCLOB达梦没有原生JSON类型用CLOB存储应用层解析ENUM/SETVARCHAR CHECK约束达梦没有原生ENUM需要转换这里说一个我吃过的亏。MySQL的VARCHAR(n)在utf8mb4字符集下是n个字符达梦的VARCHAR(n)同样按字符计算看起来一致但两边数据库实际存储的编码方式有细微差异尤其是汉字占用空间的计算逻辑。如果达梦库的字符集和MySQL不一致导入后长度校验可能报错。所以建达梦库的时候字符集一定要选UTF-8没有条件也要创造条件重装一次否则后患无穷。3.2 应用SQL里的函数与分页差异数据搬过去了只是第一步应用侧SQL也得跟着适配。这里列几个最常见的差异点。分页查询是最典型的。MySQL的写法是LIMIT offset, size而达梦支持的写法是LIMIT size OFFSET offset和PostgreSQL风格类似-- MySQL SELECT * FROM user ORDER BY id LIMIT 10, 20; -- 达梦 SELECT * FROM user ORDER BY id LIMIT 20 OFFSET 10;如果你的项目用的是MyBatis PageHelper这种分页插件插件会根据数据库dialect自动生成分页SQL前提是你正确配置了达梦的dialect类否则生成的还是MySQL语法到达梦执行必报错。日期函数差异也很大。MySQL的DATE_FORMAT到达梦要改写成TO_CHAR(日期, YYYY-MM-DD HH24:MI:SS)。IFNULL可以用NVL或COALESCE替代。GROUP_CONCAT在达梦里要改写为LISTAGG。这些函数在存储过程里高频出现迁移时做个全局检索把所有可疑的MySQL函数列出来逐个改。自增主键返回值这块MyBatis的useGeneratedKeystrue对达梦有效但业务代码里如果显式调用SELECT LAST_INSERT_ID()到达梦就要改成序列的currval或达梦的IDENTITY_VAL_LOCAL()函数逻辑复杂的话建议用ORM层统一处理。3.3 存储过程、触发器的迁移策略存储过程和触发器是迁移里的深水区。DTS能自动转换一部分但转换质量不稳定我见过转换完的存储过程在达梦里语法能过一执行就报错的情况。我的实际建议是导出存储过程语句后当成普通代码逐个人工改造。改造时关注三个点。第一是变量声明方式达梦和MySQL接近但游标、异常处理块的写法有差异不能完全照搬。第二是内置函数差异存储过程里几乎不可避免会用到日期、字符串、聚合函数这些函数两边的差异非常大逐条改。第三是schema归属和权限达梦的存储过程归属于某个schema执行时要注意schema前缀应用连库的用户需要有对应执行权限。触发器这边也一样核心语法逻辑类似但触发事件定义和NEW.xxx变量在两侧的类型映射可能不一致业务赋值时类型不匹配会报错。触发器代码量通常不大人工改的成本可控关键是改完要设计几个触发场景实际触发一次验证逻辑正确性。4. 实操中踩过的坑与排查实录4.1 中文乱码数据导入后全是问号中文乱码是我遇到最多的问题前前后后踩过两次。第一次是达梦数据库安装时字符集没有选UTF-8导致导入的中文全部变成问号这个基本上只能重建实例优化重新安装时明确选择UTF-8字符集。第二次是mysqldump导出时没有显式指定字符集导出的SQL文件用的是MySQL客户端环境的默认编码如果环境不是UTF-8文件到达梦端就乱了。解决办法是导出命令加上--default-character-setutf8mb4导入之前用文本编辑器打开SQL文件确认编码。控制文件导入CSV时在dmfldr控制文件里也可以指定字符集比如CHARACTER SET UTF8两端保持一致。4.2 列名撞上SQL关键字建表一直报错大量老系统的表结构里列名直接用group、order、desc、key这种SQL关键字。MySQL对关键字的容忍度比较高很多场景下不报错但达梦的语法检查会更严格建表时直接报错。处理办法有两个一是在SQL脚本里给敏感列名加双引号绕开语法检查但这样后续所有SQL都要带引号维护起来很痛苦二是迁移前梳理列名把关键字列名统一改掉应用代码里同步修改字段映射。改列名会影响接口返回的字段名所以要和业务方提前对齐我实际项目里一般优先选第二种方案一次性改干净。4.3 视图依赖导入顺序报错“对象不存在”用mysqldump导出视图时语句顺序是按数据库字典顺序排列的不是按依赖关系排列的。结果就是视图A依赖视图B但A的定义排在前面在达梦执行时先建A报错B不存在。解决策略是把所有视图脚本单独拆到一个文件梳理依赖关系被依赖的视图先执行逐层往上导入。如果依赖关系复杂可以先按原顺序跑一遍把报错的记录记下来再根据报错信息调整顺序反复两三次就能跑通。4.4 大表导入慢到怀疑人生一开始我用disql直接执行数据SQL脚本导一张300万行的表结果一个多小时都没跑完因为每条INSERT都是单独提交事务开销极大。后来换成dmfldr批量导入几分钟就搞定。这里还有几个优化技巧导入之前先删除索引和约束导入完成后再一次性重建否则每插一行都要更新索引速度成倍下降控制文件的分隔符尽量简单不要用特别长的字符串解析开销大如果是超大表还可以关闭达梦的归档日志模式导入完成后重新开启减少日志写入开销。4.5 连接层面的SSL与驱动问题MySQL端如果开启了SSLmysqldump导出时可能报SSL连接错误命令里加一个--ssl-modeDISABLED就能跳过SSL握手。这个参数在MySQL 8.0版本里尤其常见。应用连接达梦时如果提示找不到驱动类说明应用里没有达梦的JDBC驱动jar包驱动在达梦安装目录的driver文件夹下比如DmJdbcDriver18.jar。连接不上就先用达梦客户端工具手动连一次确认用户名、密码、端口没问题再排查应用配置。端口默认是5236防火墙要放行。Navicat新版也支持连接达梦可以在连接类型里选择达梦数据库填好地址、端口、用户名即可平时开发调试用它看数据也很方便。5. 迁移后的验证与应用侧适配5.1 数据一致性三层核对迁移完成不等于真的完成数据核对必须做我一般分三层。第一层是行数核对每张表SELECT COUNT(*)两边的数字完全一致这是底线。第二层是抽样核对挑日期、金额、文本这类敏感字段随机抽数据逐字段比对。第三层是核心表全量哈希比对把每一行的所有字段拼成一个字符串取MD5两边的哈希值一致才算真正放心。第三层虽然耗时但核心表跑一遍值得尤其是有资金、订单、用户数据的库别省这一步。5.2 Spring Boot MyBatis Druid连接达梦大部分Java项目迁移完第一个遇到的就是应用连不上达梦。达梦JDBC驱动类名是dm.jdbc.driver.DmDriver连接URL格式是jdbc:dm://IP:5236。Spring Boot Druid的配置大概是这样spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://192.168.1.10:5236 username: your_user password: your_password druid: initial-size: 5 min-idle: 5 max-active: 20 validation-query: SELECT 1生产环境别用SYSDBA账号连应用这是达梦的超管账号权限过大。新建一个业务账号只授予所需表的权限安全性才有保障。MyBatis项目除了连接配置还要检查Mapper里的SQL有没有MySQL特殊写法。比如if testxxx ! null里面用了MySQL函数或者分页SQL写死了LIMIT这些到达梦都可能挂。如果在Mapper XML里的SQL不长手工改是最直接的SQL非常多的话建议做一个SQL静态扫描工具把MySQL特征语法找出来批量改。MyBatis Plus本身对达梦的支持还不错注意分页插件要配置正确的dialect。Hibernate用户要特别注意达梦没有官方Hibernate方言需要自己配置一个方言类否则自动生成的SQL可能带MySQL的特征语法执行时报错。5.3 达梦日常运维要点项目上线之后达梦的运维操作和MySQL差异不小。图形化管理工具是DM管理工具命令行工具是disql备份恢复用DMRMAN。日常需要关注的点包括表空间使用率、数据文件大小、数据库日志报错、活动会话数、慢SQL。达梦慢SQL可以从两个地方看一是开启SQL日志后分析日志文件二是查动态性能视图中执行时间长的SQL。备份策略要提前设置好建议至少每天做一次全量备份业务高峰时段别做备份避免影响性能。熟悉了这些基本操作之后从MySQL迁移到达梦的切换阶段就能平稳度过了。6. 从一次性迁移走向常态化迁移6.1 脚本化迁移让三分钟复用如果整个流程只跑一次手工操作完全没问题。但现实情况往往是先把数据迁到测试环境应用测试发现问题修复SQL或表结构然后清掉数据重新迁一遍反复好几次。这就要把流程脚本化。我的做法是维护一个迁移脚本目录里面放结构导出脚本、结构改写脚本、数据导出脚本、dmfldr控制文件、导入脚本、校验脚本每个脚本都是可重复执行的。第一次跑通之后后面再迁移只需要改数据库连接串和库名其他代码都不用动这时候你就真正体会到三分钟迁移的价值了。6.2 数据中台场景下的持续同步思路如果做数据中台或异构系统整合迁移就不是一次性替换那么简单了而是多个系统间持续的数据同步。这时候除了一次性迁移工具还需要考虑实时同步链路比如基于日志的CDC工具把MySQL的binlog变更实时同步到达梦。相比一次性迁移持续同步对数据校验的要求更高要建立周期性的对账机制保证两端数据最终一致。先把一次性迁移的流程跑顺、脚本化、验证好做持续同步时就能复用一套标准的校验逻辑整体的迁移治理体系也会更成熟。最后再说一个我个人的经验。三分钟完成MySQL到达梦的迁移完全可行但背后要提前做足功课导出参数的细节、SQL方言差异、字符集控制、批量加载工具的热练使用每一项都得提前排查。真正动手之前强烈建议别拿生产库直接练手先用最小数据集把全流程跑一遍把坑都踩完再对全量数据操作。这套流程跑顺之后你会发现在两个数据库之间搬数据本质上就是一套统一的导出、改写、加载、校验动作。难的不是迁移本身而是对两个数据库特性差异的理解深度。
阅读完成 · 觉得有帮助?
咨询建站