news 2026/10/13 4:18:18

MySQL迁移达梦数据库:SQL语法差异与改造实践清单

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL迁移达梦数据库:SQL语法差异与改造实践清单

做数据库迁移这事,真正让人头疼的从来不是数据搬不动,而是搬过去之后应用跑不起来。MySQL 迁到达梦(后面统一叫 DM)就是典型场景:表面看都是关系型数据库,写个 SELECT、INSERT 没啥区别,但真把手写 SQL 从 MySQL 挪过去,LIMIT、IFNULL、反引号、DATE_FORMAT、ON DUPLICATE KEY UPDATE……一个接一个报错,等到联调阶段全暴露的时候,光排查就能耗掉一大半工期。我把实际走完一条迁移链路遇到的高频 SQL 语法问题、等价改造方案和整条迁移路径完整梳理了一遍,给准备做同类迁移的开发者一份能直接照着干的清单。

下面按“迁移前盘点 → 差异对照 → SQL 改造 → 数据搬迁 → 问题排查 → 应用适配”的顺序展开,适合正在做数据库替换的 DBA 和后端开发,尤其项目里大量手写 SQL、用 MyBatis 的同学。

1. 迁移前的整体思路:先盘点,再动手

1.1 迁移范围与风险盘点

接到迁移任务别急着装工具导数据。我接手时做的第一件事是盘资产:总共有多少个库、多少张表、哪些是核心业务表,视图、存储过程、触发器、定时任务里有没有直连 SQL。这一步的产出是一份资产清单,它直接决定后面要投入多少人力改代码。

盘点动作我推荐拆成四条线同时走:

  1. 用 mysqldump 导出全部库表结构、索引、约束、存储过程和视图定义,存成文本留档。后续所有转换都以这份基线为准。
  2. 在代码仓库里全局搜 SQL,把 DAO 层、XML 文件、存储过程、定时任务脚本里的手写 SQL 全部捞出来,按增删改查、分页、条件过滤、聚合统计分类打标。
  3. 统计每张表的行数和数据大小,标注哪些是大表、哪些可以归档后导入。这一步决定迁移窗口的长短。
  4. 梳理应用连接 MySQL 的方式,JDBC 驱动、连接池、ORM 框架的版本全部列清楚,因为从页面到驱动、方言配置、连接参数,迁移时都要跟着换。

这里有个容易被忽略的点:DM 的初始化参数,特别是页大小和字符集,建库定下来之后很难改。页大小直接影响单行数据能塞多少字节、大字段的索引怎么建,字符集影响中文和特殊符号能不能正常存取。所以迁移前期就要想清楚目标库用多大页、什么字符集,别等导数据报“行超长”了再回头重建库。

1.2 兼容模式选型:能省事,但不能全靠它

DM 的一个实用设计是兼容模式,配置之后可以让数据库在语法和部分行为上更接近 Oracle、SQL Server 或 MySQL。我的建议是:如果来源是 MySQL,就把兼容模式配成 MySQL。好处很明显,反引号、一部分 MySQL 习惯性写法能少改一点,迁移工具做类型映射时也少出幺蛾子。

但注意,“接近”不等于“兼容到底”。MySQL 特有的ON DUPLICATE KEY UPDATE、INSERT IGNORE、REPLACE INTO、ENGINE=InnoDB这类写法,即使开了兼容模式,DM 照样不认。我在试点阶段就吃过这个亏,以为开了兼容模式就高枕无忧,结果建表脚本直接栽在CHARSET参数上。所以兼容模式只能当减震器,不能当保险箱,该做的 SQL 审查一步都不能省。

实战建议:把兼容模式写在迁移设计文档的第一行,并且要求所有参与改造的开发都知道这个前提,否则很容易出现“本地测试没问题,一上生产就报错”的情况。

1.3 先做试点,沉淀差异清单

大项目别一步到位。我们正式迁移前先找了一个只有几十张表、但业务场景覆盖较全的小系统做试点,从建库、导 schema、导数据、改 SQL、回归测试完整走了一遍。试点系统的选择标准很简单:一定要包含分页、日期处理、自增列、多表关联、聚合统计、特殊字符这几类典型场景,不然试点的参考价值大打折扣。

试点最大的产出不是数据迁过去了,而是一份“MySQL → DM 差异清单”。每踩到一个坑,就补一条映射规则:原写法是什么、报错是什么、等价改法是什么、有没有连带影响。后面的核心系统迁移直接套这份清单,效率提高非常多,而且清单还能直接变成回归测试用例集的底稿。

2. 类型、函数与语法:MySQL 和 DM 的差异对照

2.1 数据类型映射表与转换规则

数据迁移的第一步是 schema 转换,把所有 MySQL 建表语句翻译成 DM 能执行的建表语句。类型映射是最机械也最容易出错的一步,我常用的对照关系如下:

MySQL 类型DM 推荐类型说明
TINYINTTINYINT / SMALLINTTINYINT(1) 常用作布尔,迁移后要确认应用取值
SMALLINTSMALLINT直接对应
MEDIUMINTINTDM 没有 MEDIUMINT,扩一档
INTINT直接对应
BIGINTBIGINT直接对应
BIGINT UNSIGNEDBIGINTDM 不支持 UNSIGNED,需确认无超范围
DECIMAL(m,n)DECIMAL(m,n)精度可保留
FLOAT / DOUBLEFLOAT / DOUBLE注意浮点比较场景的精度问题
BIT(1)BIT布尔语义要单独处理
CHAR(n)CHAR(n)长度单位受 DM 参数影响,见下文
VARCHAR(n)VARCHAR(n)同上,务必确认长度单位
TEXTTEXT / CLOB建议按长度选,大的转 CLOB
LONGTEXTCLOB大文本统一 CLOB
BLOBBLOB直接对应
DATEDATE直接对应
DATETIMEDATETIME直接对应
TIMESTAMPTIMESTAMP关注默认值和自动更新行为
TIMETIME直接对应
ENUMVARCHAR + CHECK建议显式拆分
SETVARCHAR / 子表不建议保留,应用逻辑要改
JSONJSON / VARCHAR新版支持 JSON,旧版先存文本

有几个容易翻车的地方值得多说一句。第一,MySQL 里大量的BIGINT UNSIGNED在 DM 里不支持,迁移工具有的会直接报错,有的会静默改成更大的类型,我建议统一处理成 BIGINT,然后人工确认应用里没有负数或超范围的隐式依赖。第二,ENUM看起来两家都支持,但语义和排序规则不一样,稳妥做法是拆成VARCHAR + CHECK 约束,同时把应用里的枚举判断逻辑过一遍。第三,DM 建库时有个LENGTH_IN_CHAR参数,控制字符串类型的长度单位是按字符还是按字节。MySQL 的varchar(n)明确是字符数,所以 DM 这边最好也把该参数打开,否则同样的varchar(255)在 UTF-8 下实际只能存不到 100 个汉字,应用正常写入直接报超长,这类问题不提前做约束测试,上线必炸。

2.2 函数差异:一张表解决 90% 的替换工作

函数替换是手写 SQL 改造里工作量最大的一块。MySQL 的函数名和 DM 差异不小,而且很多是“看起来差不多、细节差很远”,比如DATE_FORMAT和TO_CHAR的格式串完全不是一套语法。我整理了一张自己迁移时反复用的对照表:

场景MySQL 写法DM 推荐写法
当前时间NOW()SYSDATE / CURRENT_TIMESTAMP
当前日期CURDATE()CURRENT_DATE
空值兜底IFNULL(a, b)NVL(a, b)
条件取值IF(cond, a, b)CASE WHEN cond THEN a ELSE b END
日期格式化DATE_FORMAT(ts, '%Y-%m-%d %H:%i:%s')TO_CHAR(ts, 'YYYY-MM-DD HH24:MI:SS')
日期加一天DATE_ADD(ts, INTERVAL 1 DAY)DATEADD(DAY, 1, ts)
字符串拼接CONCAT(a, b)CONCAT(a, b) 或 a || b
行转列聚合GROUP_CONCAT(x)LISTAGG(x, ',') WITHIN GROUP (ORDER BY x)
截取分隔子串SUBSTRING_INDEX(str, ',', 2)INSTR + SUBSTR 组合
定位子串LOCATE('a', str)CHARINDEX('a', str) 或 INSTR(str, 'a')
正则匹配REGEXPREGEXP_LIKE
获取自增 idLAST_INSERT_ID()IDENTITY() / SCOPE_IDENTITY()

替换函数看着是翻译题,实际操作里几个细节特别容易出错。IF()的嵌套场景,MySQL 写三层很常见,改成 CASE WHEN 时要一层层包好,少一个 END 直接语法错。DATE_FORMAT的%i(分钟)和TO_CHAR的MI长得很像,批量替换后建议用真实数据跑一遍,别只看语法对不对。GROUP_CONCAT换成LISTAGG时,记得带上WITHIN GROUP (ORDER BY ...),否则结果顺序不稳定,测试时统计值对不上,排查起来很费劲。

2.3 标识符、关键字与建表选项的坑

MySQL 写惯了的人特别喜欢用反引号包表名和字段名,DM 默认不认反引号,标识符统一用双引号。我的改造原则是:代码里能不用就不加引号,必须加的时候(比如遇到保留字)统一用双引号,并且全局搜一遍反引号,确保没有漏网的。

建表语句里 MySQL 常见的ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=...,DM 完全不认。迁移工具导 schema 时会自动过滤,但自己写脚本时一定要记得去掉。另外 MySQL 里灵活的表选项,比如行格式、压缩、分区策略,DM 大多有自己的一套,不是简单翻译能解决的,建议建表后按 DM 的分区、索引规范重新设计一遍,而不是无脑对应。

关键字冲突是我觉得最隐蔽的一类问题:MySQL 里能正常当列名的词,在 DM 里可能是保留字。我们项目就撞过一张表带TYPE字段,MySQL 跑得好好的,DM 建表直接报“关键字不正确”。这类问题靠静态扫描很难穷举,最靠谱的办法是迁移前把建表脚本全部在目标库执行一遍,让数据库自己报错,再集中处理。

3. 高频 SQL 问题改造实操

3.1 分页查询的两种改法

MySQL 的分页最常用LIMIT offset, count,DM 在普通场景也能用LIMIT count OFFSET offset这类写法,但深分页的性能问题两边是一模一样的。你把LIMIT 100000, 20原样搬过去,会发现翻页越深越慢,原因也简单:数据库得先扫描到第 100000 行才开始取 20 条,前面大量行都白扫了。

-- MySQL 原来的写法 SELECT * FROM orders ORDER BY id LIMIT 100000, 20; -- DM 键值分页改造 SELECT * FROM orders WHERE id > :lastId ORDER BY id LIMIT 20;

改造思路有两个。第一,键值分页。业务上如果允许,用主键或唯一键做游标,下一页传上一页最后一条的 id,每页都是索引定位加取 20 条,速度稳定。第二,窗口函数。排序条件复杂、不能用主键游标时,用ROW_NUMBER() OVER (ORDER BY ...)包一层子查询,外层取行号范围。DM 对窗口函数的支持还可以,但要注意排序字段上有没有索引,没有索引性能还是上不去。

如果项目用的是 MyBatis 的 PageHelper,分页插件本身有方言适配,理论上会自动给 DM 生成对应分页 SQL。但注意:老版本插件的方言列表里可能没有 DM,识别不出来的时候会按 MySQL 语法生成,直接报错。建议提前在目标环境用真实分页接口跑一遍,别等联调才暴露。

3.2 自增列迁移:IDENTITY 不只是改个关键字

MySQL 的自增列用AUTO_INCREMENT定义,DM 对应的写法是IDENTITY。迁移工具在导 schema 时一般能做这个转换,但真正麻烦的在后面。

-- MySQL CREATE TABLE t_order ( id BIGINT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL ); -- DM CREATE TABLE t_order ( id BIGINT IDENTITY(1,1) PRIMARY KEY, order_no VARCHAR(32) NOT NULL );

第一是数据导入之后自增序列种子问题。如果导入时把自增列的历史值也带过去了,MySQL 那边自增种子是“最大值 + 1”,DM 的 IDENTITY 种子不一定自动对齐,应用插入新数据时可能撞上已存在的主键。解决办法是导入完成后,把 IDENTITY 种子手工推进到当前最大值加 1,或者先不让自增列生效,数据导完再补设置。

第二是应用取新 id 的代码。MySQL 用LAST_INSERT_ID(),DM 对应的函数名在不同版本里不太一样,常见的有IDENTITY()或SCOPE_IDENTITY(),而且必须和插入语句在同一个事务里才有意义。这类函数的兼容性细节别只看文档,要在目标环境实测一次。我习惯建一个最小用例,插入一条数据马上取 id,验证驱动、连接池到 SQL 的全链路都通。

第三是“插入时显式指定自增值”的场景。MySQL 允许应用手动给自增主键插值,DM 默认对 IDENTITY 列插显式值是报错的,需要走SET IDENTITY_INSERT 表 ON这种开关,用完再关掉。批量脚本迁移历史数据时特别容易踩,代码里要预留这个逻辑。

3.3 特殊 INSERT 语句的等价改写

MySQL 几个非常顺手的写入语法,DM 全都不支持,这是改造中的重灾区:INSERT ... ON DUPLICATE KEY UPDATE、REPLACE INTO、INSERT IGNORE、还有INSERT INTO t SET col=val这种“类赋值”写法。

-- MySQL 写法 INSERT INTO account(id, balance) VALUES(?, ?) ON DUPLICATE KEY UPDATE balance = balance + ?; -- DM 等价改写(MERGE) MERGE INTO account t USING (SELECT ? AS id, ? AS balance) s ON (t.id = s.id) WHEN MATCHED THEN UPDATE SET t.balance = t.balance + s.balance WHEN NOT MATCHED THEN INSERT (id, balance) VALUES(s.id, s.balance);

我的改造原则是先分场景,再选方案。业务上明确要做“存在则更新、不存在则插入”,用MERGE INTO改写,MERGE 语法接近 Oracle,语义清晰,批量性能也不差。业务上只是“不想因为重复插入直接崩溃”,优先改成“先 SELECT 判断 + 再 INSERT”,或者捕获唯一键冲突异常做兜底。不要什么都上 MERGE,写起来复杂度高,锁开销也比普通 INSERT 大。INSERT INTO t SET col=val严格来说不是标准 SQL,老项目里真不少见,搜索时建议用跨行正则单独建一条扫描规则,别和 UPDATE 的 set 混在一起。

这里有个非常实用的技巧:提前写一套“等价改写对照”文档,每个 MySQL 特殊语法都配一个 DM 可执行的示例。测试时直接对比改写前后行为,比如重复插两条相同业务键的数据,分别看结果是更新、跳过还是报错,把行为差异固化下来,省得每次靠猜。

3.4 聚合与日期函数的替换细节

聚合函数这块,GROUP_CONCAT是最典型的差异。MySQL 里GROUP_CONCAT(字段)默认逗号分隔,DM 里对应LISTAGG(字段, ',') WITHIN GROUP (ORDER BY ...)。多说一句:WITHIN GROUP里的排序必须显式写,不写的话结果顺序每次可能都不一样,测试时你会以为是数据不一致,其实是排序没定义。

SUBSTRING_INDEX也是 MySQL 特有,DM 没有直接对应函数。处理“按分隔符取第几段”这种逻辑,我是用INSTR找分隔符位置,再配合SUBSTR截取,虽然写起来啰嗦,但行为可控。这种逻辑建议在应用层封装成一个小工具函数,多个 SQL 复用,别在每个语句里都拼一长串。

日期函数除了格式化替换,还要注意默认值行为。MySQL 建表常见的create_time DATETIME DEFAULT CURRENT_TIMESTAMP加ON UPDATE CURRENT_TIMESTAMP,DM 对自动更新时间的支持不如 MySQL 顺手。我的建议是表结构里去掉ON UPDATE,由应用层显式更新update_time,或者用触发器补齐。优先选应用层方案,触发器多起来会影响写入性能,而且看似自动的逻辑,出问题时排查链路反而更长。

还有一个隐蔽的场景要专门测:空字符串和 NULL 的边界。MySQL 对空串和 NULL 分得很清楚;DM 在某些模式下可能把空串等同 NULL,导致NOT NULL DEFAULT ''的字段查出来变成 NULL,前端展示直接出 bug。这个差异不报错,但数据语义已经变了,必须放进一致性校验里专门测。

4. 数据迁移工具与完整实操流程

4.1 工具选型:自带工具和自研同步怎么配

DM 自带图形化的数据迁移工具,从界面里建好数据源就能把 MySQL 的数据迁到 DM,自动做一部分类型映射,适合中小表和初次上手。用自带工具图省事,但要注意两个点:一是大表迁移建议手工分片,工具默认把一整张表作为一个任务单元,几千万行的表迁移过程容易内存吃紧、中途断点;二是工具生成的表结构不一定满足性能要求,索引、分区策略都可能丢,我是导完数据之后按业务场景手工补索引和分区的。

如果团队已经有数据同步底座,比如基于 DataX 或自研 ETL,可以直接把 DM 当成普通目标库接入。走这条路的优势是并行调度、断点续传、增量同步都可以复用现有能力,对数据量超大、迁移窗口短的场景更可控。我们最后是混合方案:核心大表走自研分片任务,小表和配置表走自带工具,两条线互不干扰,进度也直观。

4.2 建库建表与 schema 转换

DM 的逻辑组织方式和 MySQL 不完全一样:MySQL 是“库 + 表”的两层结构,DM 更接近“实例 + 模式 + 表”的三层结构,很多客户端工具里叫用户或模式。迁移第一步是在目标实例里建好对应模式,然后把第 2 章的映射规则落到每张表上。

建表阶段我的操作顺序是:

  1. 先建业务表,主键、唯一约束、列注释一起建好;
  2. 索引单独批量建,尤其大表,建在数据导入之前会拖慢导入速度;
  3. 外键最后补,数据导完再统一加,避免导入顺序不一致导致连环报错;
  4. 视图、存储过程、函数逐个执行验证,MySQL 的DELIMITER、DEFINER修饰在 DM 里不支持,最好先脚本批量去除,再手工排查函数体里的语法差异。

有一个我反复提醒自己的点:schema 转换不要只对着旧建表语句翻译,要结合 DM 的特性重新想一遍。比如 MySQL 的普通索引在 DM 里要不要建成复合索引、表要不要按日期分区、大字段要不要单独拆表,这些在迁移阶段做,比上线后补救便宜得多。

4.3 全量数据的搬迁与校验

数据搬迁阶段,几个实操参数供参考:单事务提交行数一般设 1000 到 5000 行,太小事务开销大,太大会拖长单事务时间、加重回滚风险;并行度根据源库和目标库的 CPU、IO 调整,别一上来就开 20 并发,源库会被拖垮,目标库也可能因为日志量过大而卡顿。字符集全程保持一致,源表是 utf8mb4,目标库就建 UTF-8,连接参数里也要明确指定,否则中文可能乱码,特殊字符可能变成问号。

数据搬完不是结束,要做两层校验。第一层是行级校验,每张表SELECT COUNT(*)两边对比,任何不一致都要查原因。第二层是字段级校验,抽关键表做分组聚合对比,比如SUM、MIN、MAX、COUNT(DISTINCT field),或者按主键做哈希校验,能发现行数一样但内容不对的隐性错误。

对时间敏感的系统,全量迁移必须提前评估窗口期。我印象很深的一次,一张八千万行的核心流水表单表迁移花了接近一个半小时,整个库挪完要到凌晨。窗口不够的话,一定得规划增量方案,下面讲。

4.4 增量追平与切换放量

业务不能长时间停的时候,全量之后必须补增量。通用套路是:全量开始前记录 MySQL 的 binlog 位点,全量结束后把期间的增量数据追到 DM,两边追平后再停写切换。这里提醒一句:DM 自带迁移工具未必支持从 MySQL binlog 实时解析增量,别把宝押在它身上。稳妥做法是复用已有数据同步中间件,或者接受一次短停,在停写窗口内完成全量加增量合并。

切换上线那天,别急着把流量全部切过去。我习惯按这个节奏来:

  1. 先切少量只读流量,观察核心接口的错误率、慢查询和告警;
  2. 只读验证没问题,再切一部分写流量,盯数据一致性和延迟;
  3. 确认稳定后逐步放量到 100%;
  4. 回滚预案提前演练:MySQL 侧保持同步到切换前一刻,DM 侧一旦异常,把流量切回 MySQL,业务最多丢切换窗口内的少量写入。

这套节奏看着慢,实际上是整个迁移里最省钱的部分。出问题不是在查监控的路上,就是在切流量的操作上,提前演练过的回滚路径能救大命。

5. 常见问题排查记录与性能调优

5.1 一张速查表解决大多数报错

迁移过程中遇到的报错五花八门,但归归类其实就那几类。我把踩过的问题整理成表,放在项目文档里给团队当速查手册:

现象可能原因解决方向
建表报“关键字不正确”列名或表名是 DM 保留字加双引号或改字段名,全链路同步改
导入中文乱码或特殊字符变问号字符集设置不一致库、连接串、客户端三层统一 UTF-8
自增列插入撞主键IDENTITY 种子没对齐最大值手工推进种子到 max(id) + 1
分页 SQL 语法报错分页插件方言不识别 DM升级插件版本或改手写键值分页
日期格式化结果全空或错乱DATE_FORMAT 没换成 TO_CHAR全局替换,注意 %Y 和 YYYY 的差异
同一 SQL 在 MySQL 快、DM 慢统计信息缺失或索引缺失执行统计信息更新,按执行计划补索引
NOT NULL 字段查出来是 NULL空串被按 NULL 处理调整兼容模式或应用侧兜底
导入长文本报“行超长”页大小不够容纳单行建库加大页大小或大字段转 CLOB
行数一致但聚合结果对不上类型映射或隐式转换问题排查 UNSIGNED、DECIMAL 精度、ENUM 排序

速查表看着简单,关键是每条都是实际砸过时间的。建议迁移项目组从第一天就开始维护这个表,每解决一个问题就补充一行,它就是项目最宝贵的知识资产。

5.2 迁移后性能变差的排查套路

数据过去了,SQL 也改了,真正上线才发现慢,这是最折磨人的场景。DM 和 MySQL 的优化器思路差异很大:原来在 MySQL 里走得好好的索引,到达梦可能因为统计信息没更新而走全表扫描,也可能因为索引选择性判断不一样而选错执行计划。

性能排查我按固定套路来。先更新统计信息,这是最便宜的一步,经常一条命令解决一半问题。再拿重点 SQL 看执行计划,对比 MySQL 里原来的计划,关注表访问方式和 JOIN 顺序。然后根据执行计划补索引,记住 DM 和 MySQL 的索引选择策略不同,不能盲目平移旧索引。最后单独排查深分页和数据倾斜,这类问题不是单条 SQL 能解决的,要从业务查询模式改。

我们项目有个两千万行的大表 JOIN,迁移后要 15 秒,最后就是补了一个在 MySQL 里完全不需要的复合索引,压到了 300 毫秒,因为 DM 优化器对多列过滤的选择策略不一样。这个案例说明:迁移不是“搬过去就完事”,性能调优阶段一定要预留时间。

5.3 字符集、连接池这些隐蔽环节

业务 SQL 都跑通了之后,还有一些隐蔽环节容易出幺蛾子。字符集是最典型的一个。DM 的 JDBC 连接串里如果不显式指定编码,客户端默认可能不是 UTF-8,表现出来就是“同一个系统,部分接口中文正常,另一部分乱码”。排查这种问题要同时看三个位置:库的字符集、JDBC 连接串参数、客户端工具设置,三层一致才敢说没问题。

连接池是另一个。MySQL 和 DM 的驱动参数名不同,MySQL 常见的校验查询SELECT 1在 DM 上不一定被正确识别,连接池探活逻辑如果没适配,会出现偶发连接中断、定期报连接不可用这类诡故障。这类问题最坑的地方在于配置在框架层,跟业务 SQL 无关,排查方向容易跑偏。我建议迁移前期就把连接池的探活语句、自动提交、事务超时这些参数全部对齐到 DM 的规范,省得后面被“莫名故障”反复折腾。

6. 应用层改造与回归经验

6.1 MyBatis、JPA 的适配要点

如果是 MyBatis 项目,大量手写 SQL 的 XML 就是重灾区。我建议先跑一遍 SQL 扫描脚本,把“必改关键字”清单自动定位出来:反引号、深分页 LIMIT、IFNULL、DATE_FORMAT、GROUP_CONCAT、ON DUPLICATE KEY UPDATE、INSERT SET 这些,全部在代码里搜出来之后再逐条手工确认。不要想着全自动替换,格式化字符串、嵌套函数、大小写、换行都会让正则失效,自动扫描只是用来定位,改造还是要人眼过一遍。

#{}参数化写法一般不用动,但${}拼接到 SQL 里的部分要额外小心。排序字段、动态表名走${}的场景经常把 MySQL 特有语法混进去,而且不好搜,建议扫源码时单独建一个动态 SQL 片段清单。

JPA/Hibernate 相对省力,把方言配置成 DM 对应的方言后,大部分 HQL 生成的 SQL 会自动适配。但@Query(nativeQuery = true)的原生 SQL 还是得走和第 3 章完全一样的改造流程,这一块很容易被忽略,因为大家默认框架会处理,实际上原生 SQL 就是裸 SQL,框架一层适配都没有。

6.2 语法回归用例集怎么建

迁移改造完成后,测试怎么证明“真的改对了”?我的做法是建一套语法回归用例集:把迁移过程中遇到过的每个问题 SQL 整理成固定用例,连同结果断言一起入库,每次改造后跑一遍。用例集不需要设计得多复杂,关键是覆盖典型场景:

  • 分页:首页、中间页、末页,以及深分页边界;
  • 日期:跨年、跨月、闰年、时间边界 23:59:59;
  • 空值和空串:NULL 字段、空串字段、NOT NULL DEFAULT ''字段;
  • 特殊字符:emoji、引号、换行、百分号;
  • 多表 JOIN:关联键为空的情况、多条件过滤的组合;
  • 聚合排序:GROUP_CONCAT / LISTAGG 的排序稳定性、去重统计。

这套用例集的成本不高,但价值非常大。联调阶段所有“这个 SQL 好像没问题啊”的争论,都可以直接用用例集跑一遍来裁决,不用靠感觉。

6.3 上线切换与回滚预案

上线切换的细节在第 4.4 节说了不少,这里补充几个和团队协作相关的经验。切换当天一定要有一个“总控 + 执行 + 观察”的明确分工:谁负责执行脚本、谁盯着监控、谁在出问题时喊停,提前写清楚并排练一遍。数据库迁移这种操作,最怕的是所有人同时上手,你改你的、我查我的,出了问题互相不知道谁动了什么。

回滚预案不是写个文档就完事。MySQL 侧的备份、连接信息、账号权限要一直保留到业务在 DM 上稳定运行两周以上,不要切换成功当天就清理。我见过不少项目切完就删旧库,结果新库有个隐藏性能问题,想对比原库行为都没得比,只能干等。

最后分享一个我自己的经验:迁移完成后,尽量保留一条能连接旧 MySQL 环境的通道。很多边界行为,比如空串处理、浮点精度、字符排序,光看文档说不清楚,直接在两个库上跑同一条 SQL 看结果,比翻三天文档都快。这条通道在稳定运行两周后可以关,但在那之前,它是排查一切疑难杂症的底气。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 4:18:15

递归求单链表结点个数:从代码实现到内存与栈安全的工程实践

1. 这不是一道“刷题”题,而是一把打开数据结构思维的钥匙“递归求解单链表中的结点个数”——看到这个标题,很多人第一反应是:哦,这是《数据结构与算法》课后习题第3章第2题,用递归写个count函数就完事了。但在我带过…

作者头像 李华
网站建设 2026/10/13 4:18:01

MySQL跳过身份验证重置root密码:原理、实操与安全收尾

1. 什么情况下才需要这招:先判断问题真伪先说一个我印象特别深的场景。某天快下班的时候,一个同事跑过来说测试库连不上了,报错是Access denied for user rootlocalhost。他第一反应是密码被人改了,准备直接停库重装。我当时拦住了…

作者头像 李华
网站建设 2026/10/13 4:17:35

Databricks性能优化实战:从架构到Delta Lake的全面指南

如果你做过数据平台、数仓,或者只是把 Spark 当作日常作业引擎用过一阵子,那“Databricks”这个名字大概率绕不开。我接触这个平台也是从一次事故开始的:线上数仓作业莫名其妙从十分钟涨到三小时,老板盯着看板,我盯着一…

作者头像 李华
网站建设 2026/10/13 4:17:06

EPLAN电气设计超实用指南:项目图纸结构、操作流程与故障排查

搞电气设计这些年,最不后悔的一件事,就是早点把EPLAN用了起来。你可能也遇到过这种场景:用纯CAD画电气原理图,画到几十页之后,改一个点位编号要全局搜索替换,核对端子排和电缆清册要对着图纸一条条数&#…

作者头像 李华
网站建设 2026/10/13 4:16:43

RPGMZ插件列表实战:从插件冲突到参数配置与插件开发

简介:面向RPG Maker MZ开发者的插件集合,围绕游戏系统扩展打包了技能树、炼金合成、虚拟按键、任务追踪、商店界面、装备状态、队伍编制、战斗中断等常用功能,可直接用于增强项目的玩法深度与操作体验。压缩包共29个文件,其中27个…

作者头像 李华
网站建设 2026/10/13 4:16:42

多标签文本分类三大实战方案:图神经网络、Seq2Seq与层级分类

1. 这不是文献综述,是三年前那几篇让我反复调试模型的“硬核论文”实操笔记2019年那会儿,多标签文本分类还没被大模型带火,但实际业务里早就在啃硬骨头了——电商商品要打“保暖加厚纯棉韩版”四五个标签,医疗问诊记录得同时归类到…

作者头像 李华