1. 项目缘起:当MySQL遇见达梦,迁移的必然与挑战
最近几年,身边不少朋友和同事的项目都开始从MySQL向国产的达梦数据库迁移。有的是因为项目本身有信创要求,必须使用国产化技术栈;有的则是看中了达梦在复杂查询、高并发事务处理上的一些特性。但不管原因是什么,大家遇到的第一个拦路虎几乎都是同一个:数据怎么搬过去?
我干了十多年数据库运维,经手的数据迁移项目少说也有几十个。从早期的Oracle到MySQL,再到现在的各种国产数据库,每次迁移都像是一次“搬家”——数据就是你的全部家当,不能丢、不能乱、更不能坏。这次,我就把MySQL数据导入达梦数据库这个活儿,从头到尾、掰开揉碎了讲清楚。网上能找到的教程要么太零散,要么只讲工具操作,背后的原理和踩过的坑却很少提。这篇文章,我会结合最新的达梦8版本和MySQL 5.7/8.0,从环境准备、工具选型、实操步骤到排错优化,给你一份能直接照着做的“保姆级”指南。
2. 迁移前的战略准备:不只是装个工具那么简单
很多人一上来就急着找数据导出导入工具,这其实是本末倒置。迁移的成功,七分靠准备,三分靠执行。在动任何一条数据之前,我们必须把“家底”摸清,把“路线图”画好。
2.1 环境与版本兼容性盘点
这是第一步,也是最容易出问题的一步。达梦数据库和MySQL在架构、语法、数据类型上存在天然差异,版本选择直接影响迁移工具的可用性和迁移过程的顺畅度。
源端(MySQL)需要确认的信息:
- MySQL版本:是5.5、5.7还是8.0?不同版本在字符集、JSON支持、系统表结构上差异巨大。例如,MySQL 8.0默认的字符排序规则(collation)是
utf8mb4_0900_ai_ci,这在老版本迁移工具中可能不被识别。 - 字符集与排序规则:执行
SHOW VARIABLES LIKE 'character_set_database';和SHOW VARIABLES LIKE 'collation_database';。最常见的是utf8mb4。达梦对utf8mb4有很好的支持,但排序规则名称可能不同,需要映射。 - 存储引擎:
SHOW ENGINES;查看。如果大量使用MyISAM,迁移到达梦(其表类似InnoDB,支持事务)时,需要考虑表级锁到行级锁的转变可能带来的应用逻辑隐含变化。虽然数据能导过去,但行为可能微调。 - 特殊对象:检查是否有存储过程、函数、触发器、视图。MySQL的这些对象语法与达梦的PL/SQL风格差异较大,基本无法直接迁移,需要重写。这是迁移中工作量最大的部分之一。
目标端(达梦)需要准备的事项:
- 达梦版本:建议使用达梦8。相比达梦7,DM8对MySQL的兼容模式(COMPATIBLE_MODE参数)支持更好,能自动处理更多语法和数据类型映射。你可以通过达梦数据库管理工具(DM Management Tool)或命令行
SELECT * FROM V$VERSION;查看。 - 安装与参数调优:安装过程网上教程很多,这里不赘述。关键是在初始化数据库实例时,根据数据量预估合理设置页大小(PAGE_SIZE)、簇大小(EXTENT_SIZE)和日志文件大小。对于从MySQL迁移,一个重要的参数是
COMPATIBLE_MODE。在dm.ini文件或管理工具中,将其设置为4,即开启MySQL兼容模式。这会让达梦更“宽容”地对待一些MySQL特有的语法。 - 创建目标用户与表空间:规划好目标数据的归属。不要直接用SYSDBA账号导入业务数据。应该为迁移项目创建独立的用户和表空间,便于权限管理和空间控制。
2.2 核心工具选型与深度解析
工欲善其事,必先利其器。针对MySQL到达梦的迁移,主要有以下几类工具,各有优劣。
1. 达梦官方迁移工具(DTS)这是达梦数据库自带的数据迁移工具,在安装达梦客户端后即可找到。它应该是你的首选。
- 工作原理:DTS通过JDBC连接源库和目标库,从源库元数据中读取表结构,根据内置的映射规则转换为达梦的DDL语句创建目标表,然后通过
SELECT * FROM source_table和INSERT INTO target_table的方式逐批迁移数据。 - 优点:
- 官方出品,兼容性最好:对达梦的数据类型映射、语法转换处理得最权威。
- 图形化界面,操作直观:适合不熟悉命令行的DBA或开发者。
- 支持全量和增量迁移:可以配置定时任务,持续同步变化数据。
- 缺点与坑点:
- 对MySQL驱动版本敏感:这是最常踩的坑!工具报错“no default drivers found.”或连接失败,十有八九是驱动问题。DTS可能自带较老的MySQL JDBC驱动(如5.x),无法连接MySQL 8.0(需要8.x驱动)。解决方法是将最新的
mysql-connector-java-8.0.xx.jar放入DTS工具的/drivers/jdbc目录下。 - 大数据量性能一般:对于亿级以上的单表,逐批
INSERT的方式可能会比较慢,且产生大量日志。 - 复杂对象处理能力弱:对于存储过程、自定义函数等,基本无法自动转换。
- 对MySQL驱动版本敏感:这是最常踩的坑!工具报错“no default drivers found.”或连接失败,十有八九是驱动问题。DTS可能自带较老的MySQL JDBC驱动(如5.x),无法连接MySQL 8.0(需要8.x驱动)。解决方法是将最新的
2. 使用第三方通用数据库工具例如DBeaver、Navicat Premium。这些工具通常也提供了跨数据库的迁移功能。
- 工作原理:与DTS类似,通过JDBC/ODBC连接,进行结构和数据的传输。Navicat Premium版本甚至可以直接连接达梦数据库(需要配置ODBC驱动)。
- 优点:如果你已经熟悉这些工具,上手快,一个工具管理多种数据库。
- 缺点:
- 映射规则可能不精确:不如官方工具专业,在数据类型转换(如MySQL的
DATETIME到达梦的TIMESTAMP)、默认值处理上可能出错。 - 同样面临驱动问题:需要手动配置和测试数据库驱动连接。
- License成本:Navicat等商业工具需要购买。
- 映射规则可能不精确:不如官方工具专业,在数据类型转换(如MySQL的
3. “导出SQL文件 -> 修改 -> 到达梦执行” 手工流这是最原始但也最可控的方法。使用mysqldump命令导出MySQL的数据和结构为SQL文件,然后用文本编辑器或脚本进行修改,最后到达梦数据库中用命令行工具disql或管理工具执行。
- 工作原理:完全手动控制转换过程。
- 优点:绝对可控,可以处理任何复杂情况,适合迁移对象不多但结构复杂、定制化程度高的场景。也是排查自动工具迁移失败原因的最后手段。
- 缺点:工作量巨大,容易出错,不适合大规模迁移。
我的建议:对于大多数迁移场景,首选达梦官方DTS工具。在正式迁移前,用一个小的测试库完整跑一遍流程,验证工具链的可靠性。
3. 实战演练:使用达梦DTS完成一次完整迁移
假设我们要将一个名为test_db的MySQL数据库(版本5.7,字符集utf8mb4)迁移到达梦8。下面是用DTS进行迁移的详细步骤和每个环节的注意事项。
3.1 步骤一:驱动准备与源库连接
- 获取MySQL驱动:前往MySQL官网或Maven仓库,下载
mysql-connector-java-8.0.xx.jar(即使源库是5.7,也建议用8.0驱动,兼容性更好)。 - 放置驱动:找到达梦DTS工具的安装目录(例如
/opt/dmdbms/tool/dts),将下载的JAR文件放入其子目录/drivers/jdbc中。如果该目录不存在,可以手动创建。 - 启动DTS:在达梦安装目录下找到
dts可执行文件并运行。 - 新建迁移工程:在DTS中新建一个“迁移工程”。
- 配置MySQL源库连接:
- 连接类型:选择
MySQL。 - JDBC驱动类:通常会自动识别,如果未识别,手动填写
com.mysql.cj.jdbc.Driver(8.x驱动) 或com.mysql.jdbc.Driver(5.x驱动)。 - URL:格式为
jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC。注意serverTimezone参数,避免时区问题导致的时间字段错误。 - 输入用户名和密码,点击“测试连接”。务必确保测试成功。
- 连接类型:选择
注意:如果遇到“Public Key Retrieval is not allowed”错误,需要在URL连接字符串后追加
&allowPublicKeyRetrieval=true。如果遇到时区问题,可以将serverTimezone设置为Asia/Shanghai。
3.2 步骤二:迁移策略与对象选择
连接成功后,DTS会读取源库的元数据,列出所有表、视图等对象。
- 选择迁移模式:通常选择“结构+数据”。如果只想迁移结构,或只追加数据,可按需选择。
- 筛选迁移对象:在对象列表里,勾选需要迁移的数据库和表。这里有一个重要技巧:不要一次性全选所有表。建议先选择几个具有代表性的表(包含各种数据类型:int, varchar, datetime, text, decimal等)进行试迁移。这能提前暴露数据类型映射、默认值、注释等方面的问题。
- 配置迁移选项(关键!):
- 表结构迁移选项:
- 约束和索引:一般勾选“迁移主键”、“迁移唯一约束”、“迁移外键”、“迁移索引”。但要注意,如果MySQL表有全文索引(FULLTEXT),达梦可能不支持,需要忽略或后期用其他方式实现。
- 默认值:务必勾选。MySQL中
CURRENT_TIMESTAMP这样的默认值,DTS会尝试转换为达梦的等效函数。 - 表注释和列注释:建议勾选,保留元数据信息。
- 数据迁移选项:
- 提交行数:默认是1000。意味着每迁移1000行数据,提交一次事务。对于大数据量表,可以适当调大(比如5000或10000)以提高性能,但要注意达梦回滚段的大小,避免单事务过大导致日志膨胀。
- 遇到错误时:建议选择“忽略错误,继续执行”,并勾选“记录错误信息”。迁移完成后,务必仔细查看错误日志,处理失败的数据行。常见的错误可能是某行数据违反了目标表的约束(如唯一键重复),或者数据类型转换失败(如一个字符串无法转为数字)。
- 表结构迁移选项:
3.3 步骤三:转换规则预览与手动调整
在正式迁移前,DTS会提供一个“转换”预览界面。这是避免踩坑的黄金环节,一定要仔细检查!
- 查看DDL转换:点击任意一张表,查看DTS为它生成的达梦建表语句。重点关注:
- 数据类型映射:
varchar(255)是否正确映射?datetime是否映射为timestamp?tinyint(1)(MySQL常用来表示布尔值)是否被映射成了tinyint?在达梦里,更规范的布尔类型是BIT,但应用层可能需要调整读取逻辑。 - 默认值和函数:
CURRENT_TIMESTAMP是否被正确转换?MySQL的ON UPDATE CURRENT_TIMESTAMP属性,达梦可能无法直接支持,需要后期通过触发器实现。 - 自增列:MySQL的
AUTO_INCREMENT,达梦会转换为IDENTITY(1,1)。检查起始值和步长是否正确。
- 数据类型映射:
- 手动编辑:如果发现转换不符合预期,可以在预览窗口直接编辑DDL语句。例如,你觉得
TEXT类型映射的精度不够,可以手动改为CLOB。编辑后,这个修改只会影响本次迁移。
3.4 步骤四:执行迁移与监控
确认无误后,点击“执行”。DTS会先迁移结构(创建表、索引等),再迁移数据。
- 监控进度:观察迁移日志,关注“成功”、“警告”、“错误”的数量。警告可能是一些非致命问题,如注释格式不支持;错误则需要立即关注。
- 性能观察:在达梦数据库服务器上,可以使用达梦的性能监控工具或命令行(如
v$sessions视图)观察导入期间的I/O和CPU使用情况。如果速度异常慢,可能是:- 目标表建立了太多索引。可以考虑先迁移数据,迁移完成后再创建索引,速度会快很多。
- 单次提交行数设置太小,频繁提交事务产生大量日志。
- 网络或磁盘I/O瓶颈。
迁移完成后,DTS会生成一份报告。务必导出并保存这份报告和详细的错误日志,这是后续数据核对和问题追溯的依据。
4. 迁移后的核心动作:校验、优化与适配
数据导进去,只是万里长征第一步。确保数据准确、系统稳定运行,才是终点。
4.1 数据一致性校验
这是绝对不能跳过的环节。自动化工具不是100%可靠。
- 记录数校验:这是最基本的。分别在MySQL和达梦中对每个表执行
SELECT COUNT(*) FROM table_name;,比对数量是否一致。注意,如果迁移过程中选择了“忽略错误”,这里数量可能就不一致,需要根据错误日志定位丢失的数据。 - 抽样内容校验:对于关键业务表,不能只相信计数。编写一些校验脚本:
- 哈希校验:对于大表,可以按主键分段,计算MD5或CRC32校验和。例如,在MySQL和达梦中分别执行:
SELECT SUM(CRC32(CONCAT_WS('|', col1, col2, col3))) FROM table WHERE id BETWEEN 1 AND 10000;比对结果。CONCAT_WS用于将多列拼接成一个字符串,CRC32计算其哈希值。这种方式比逐行比对高效得多。 - 关键字段统计:对数值型字段,比较
SUM,AVG,MAX,MIN等统计值。 - 随机行比对:随机抽取几十到几百行数据,将完整行数据导出到文件,进行逐字段比对。
- 哈希校验:对于大表,可以按主键分段,计算MD5或CRC32校验和。例如,在MySQL和达梦中分别执行:
4.2 性能与兼容性调优
数据迁移后,同样的查询在达梦上性能可能天差地别,需要针对性优化。
- 更新统计信息:数据刚导入,达梦的优化器对表的数据分布一无所知。立即对迁移过来的所有表执行统计信息收集:
DBMS_STATS.GATHER_TABLE_STATS('SYSDBA', 'TABLE_NAME');或者使用管理工具右键菜单中的“更新统计信息”功能。这对查询性能有立竿见影的效果。 - 索引重建与优化:迁移过来的索引可能因为数据插入方式而产生较多的碎片。对于核心大表,考虑重建索引:
ALTER INDEX index_name REBUILD;。 - SQL兼容性适配:这是应用改造的重点。组织开发团队,对应用中的所有SQL语句进行回归测试。常见的不兼容点包括:
- 分页语法:MySQL用
LIMIT offset, row_count,达梦用LIMIT row_count OFFSET offset或更兼容的SELECT * FROM ... OFFSET ... FETCH NEXT ...。 - 字符串函数:
DATE_FORMAT->TO_CHAR,IFNULL->NVL或COALESCE。 - 系统函数:
NOW()->SYSDATE。 - 自增列获取:MySQL的
LAST_INSERT_ID(),达梦用IDENTITY()。 INSERT ... ON DUPLICATE KEY UPDATE:这个MySQL特有语法达梦不支持,需要改写为MERGE INTO语句。
- 分页语法:MySQL用
- 应用连接池配置:将应用中的数据库连接URL、驱动类名、用户名密码切换为达梦的配置。达梦的JDBC URL类似
jdbc:dm://host:port/DATABASE,驱动类为dm.jdbc.driver.DmDriver。
4.3 特殊对象的迁移策略
对于存储过程、函数、触发器等,DTS基本无能为力,需要手工重写。
- 导出源码:在MySQL中使用
SHOW CREATE PROCEDURE proc_name;或通过mysqldump -R(导出 routines)来获取这些对象的定义。 - 语法转换:这是一个细致活,核心是理解两者编程语言的差异:
- 变量声明:MySQL用
DECLARE var INT DEFAULT 0;,达梦PL/SQL用var INT := 0;。 - 循环语句:MySQL的
LOOP ... END LOOP,REPEAT ... UNTIL ... END REPEAT,到达梦需要转换为LOOP ... EXIT WHEN ... END LOOP;或WHILE ... LOOP ... END LOOP;。 - 游标:语法类似,但细节(如游标属性
%FOUND,%NOTFOUND)的用法需调整。 - 异常处理:MySQL用
DECLARE ... HANDLER,达梦用EXCEPTION WHEN ... THEN ...。 - 内置函数:所有用到的日期、字符串、数学函数都需要找到达梦中的对应函数替换。
- 变量声明:MySQL用
- 测试与验证:重写后,必须在达梦环境中创建,并使用多种边界用例进行充分测试,确保逻辑与MySQL原版完全一致。
5. 避坑指南:那些我踩过的“雷”
迁移过程中,有些错误非常典型,提前了解可以节省大量排查时间。
坑一:字符集与乱码问题
- 现象:迁移后,中文字段显示为问号(??)或乱码。
- 根因:连接链路上的字符集设置不一致。可能是MySQL端、DTS工具、达梦数据库实例、达梦客户端任何一处的字符集设置问题。
- 解决方案:
- 确保MySQL数据库、表、列的字符集为
utf8mb4。 - 在DTS连接MySQL的JDBC URL中,明确指定
characterEncoding=utf8。 - 确认达梦数据库实例初始化时指定的字符集(通常是
UNICODE或GB18030,都兼容中文)。可以在达梦中执行SELECT SF_GET_UNICODE_FLAG();,返回1表示UNICODE。 - 在达梦的
dm.ini中,可以设置LENGTH_IN_CHAR=1,让VARCHAR以字符为单位计算长度,更符合MySQL习惯。
- 确保MySQL数据库、表、列的字符集为
坑二:时间字段的时区陷阱
- 现象:所有
datetime或timestamp类型的数据迁移后,时间都差了8小时(或其他时区差)。 - 根因:MySQL中
timestamp类型会以UTC时间存储,并根据连接时区转换显示。而达梦的timestamp默认按服务器本地时间处理。如果迁移工具在传输时没有正确处理时区信息,就会导致偏差。 - 解决方案:
- 在DTS连接MySQL的URL中,强制指定时区,如
serverTimezone=Asia/Shanghai。 - 迁移后,检查达梦数据库服务器操作系统的时区设置,确保与应用预期时区一致。
- 对于要求绝对时间的业务,可以考虑在达梦中使用
TIMESTAMP WITH TIME ZONE类型。
- 在DTS连接MySQL的URL中,强制指定时区,如
坑三:自增列(AUTO_INCREMENT/IDENTITY)的断层
- 现象:迁移后,向达梦表插入新数据,自增ID不是从最大值+1开始,或者插入冲突。
- 根因:迁移工具只迁移了数据,没有正确设置表自增序列的当前值。
- 解决方案:迁移完成后,对于每个有自增列的表,手动重置自增序列。在达梦中,需要查询当前表的最大ID,然后修改表的自增列种子值。例如:
更稳妥的做法是,在DTS迁移结构时,就检查生成的DDL中-- 假设表名为 t1,自增列名为 id SELECT MAX(id) FROM SYSDBA.T1; -- 假设得到 1000 ALTER TABLE SYSDBA.T1 MODIFY id IDENTITY(1001, 1); -- 将下一个值设置为1001IDENTITY的起始值是否正确。
坑四:外键约束导致的迁移失败或循环依赖
- 现象:迁移时大量报外键约束错误,或者表创建失败。
- 根因:MySQL允许存在外键循环依赖(A引用B,B引用C,C又引用A),或者在迁移过程中,DTS未按依赖顺序创建表/插入数据。
- 解决方案:
- 在DTS的迁移选项中,暂时取消勾选“迁移外键”。先迁移所有表结构和数据。
- 迁移完成后,再通过分析原MySQL库的外键关系,在达梦上手动编写并执行添加外键的SQL语句。添加时,可以使用
ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... DISABLE;先创建为禁用状态,等所有外键创建语句都执行成功后,再批量启用,以避免循环依赖问题。
坑五:大数据量表迁移超时或内存溢出
- 现象:迁移几千万行的大表时,DTS卡住、变慢,甚至客户端崩溃。
- 根因:默认的批处理设置不适合海量数据,或者客户端JVM内存不足。
- 解决方案:
- 分而治之:在DTS中,不要一次性迁移整张大表。可以利用源表的主键或时间字段,在“迁移过滤”条件中,编写WHERE子句分批迁移。例如
id BETWEEN 1 AND 1000000,分多次任务完成。 - 调整JVM参数:找到DTS的启动脚本(如
.ini或.vmoptions文件),适当调大-Xms和-Xmx参数,给予更多内存。 - 换用更高效的工具:对于TB级数据,可以考虑使用达梦的
dimp/dexp命令行工具进行导出导入,或者编写定制化的ETL脚本,利用LOAD DATA等批量加载方式,性能远超JDBC逐批插入。
- 分而治之:在DTS中,不要一次性迁移整张大表。可以利用源表的主键或时间字段,在“迁移过滤”条件中,编写WHERE子句分批迁移。例如
迁移数据库是个系统工程,考验的不仅是工具的使用,更是对两种数据库差异的深刻理解、严谨的流程设计和细致的问题排查能力。我的经验是,永远对自动化工具保持怀疑,用多次、小范围的试迁移来验证流程,用严格的校验来保证结果。当你成功地把最后一个应用切换到新的达梦数据库并稳定运行一周后,那种成就感,是单纯敲几条命令无法比拟的。