简介:新老系统切换中的数据迁移,往往决定B端产品上线成败,也是信息化建设中外采转自研最易踩坑的环节。这份总结来自企业真实项目经验,面向产品经理、项目经理与系统实施人员,完整还原数据迁移全流程:先分析迁移场景与系统切换方式(双系统并行、一次性切换、按结算区间过渡),再梳理基础数据、字典、用户、业务及在途数据的迁移范围与关联关系处理,并对比Excel导入、数据库同步、接口传输、全量+增量等离线与在线方案的适用条件,最后给出数据验证与预演要点。文档按迁移场景、切换方式、迁移内容、迁移方式、数据验证五大模块组织,可直接用于方案设计对照。整包为1个docx文档,大小约15KB,内容紧凑、结构清晰。目前已有126人学习,适合正在处理新老系统替换或数据割接工作的从业者快速建立完整方案框架。 做过B端系统切换的人都有体会:新系统开发半年,上线前最重要但又最不起眼的环节其实是数据迁移。方案写得再漂亮,数据迁不过去,或者迁过去核对不平,切换就得延期。B端项目里,老系统往往跑了好几年,核心表单表加流水类表动辄一两百张,累计数据量十几个GB,部分大表一天新增几十万条。新系统要上线,老系统的数据不能丢、不能乱,还得保证切换后业务能无缝接续。
我最近刚完成的一个项目,正好是典型的 Oracle 12c 迁到达梦数据库(DM8)场景。迁移过程中遇到过字符集乱码、大字段丢失、序列冲突、外键顺序报错、增量同步重复数据等一系列问题。这篇文章我会把整个过程中的方案设计、兼容性排查、全量迁移、增量追平、停机切换、校验回滚的做法完整整理出来,顺手附上踩过的坑和最终的解决方式。对于正在准备数据迁移、系统切换相关工作的架构师、DBA 和后端开发,应该能帮你省下不少试错时间。
1. 方案选型与整体设计
1.1 为什么不能直接“导出导入”完事
数据迁移不是一个技术动作,而是一条工程链路。很多人第一反应是:把老库用工具导出,再导入新库,完事。真这么做,大概率会在切换当天翻车。
首先,B端业务的表结构不会完全一致。换新系统通常伴随着业务模型调整,比如老系统把客户联系方式存在一张副表里,新系统可能直接在主表加了几列;老系统的字典表用中文存,新系统改成编码。数据迁移要先做映射,而不是“把表导过去”。
其次,一致性要求高。B端数据错一条,可能就是一笔对不上的订单、一条漏掉的客户记录。迁移后必须能做行数、金额、唯一性层面的双重核验。还有一个容易忽略的点:新老系统切换往往不是“一次性复制”,而是从准备迁移到正式切换之间隔着一段时间,老系统还在持续产生新数据。方案里必须包含增量同步,否则你导完的数据只是某个时间点的快照,到切换当天又落后一大截。
1.2 我采用的“全量 + 增量 + 停机切换”三阶段方案
这次项目最终选择的是经典的三段式流程:
- 全量迁移:先把老库的表结构和存量数据整体搬到新库,得到一个基线
- 增量追平:每次按固定间隔,把老库新写入或变更的数据同步到新库,让两边尽量接近
- 停机切换:正式切换时先停老系统写入,再做最后一次增量追平,然后新系统接手
这套方案的核心思想是,把成本最高的全量迁移放到早期慢慢做,把风险最高的增量追平压缩到切换前几十分钟内完成。我们实际安排的停机窗口大约是4小时,其中真正花在“最后追平 + 校验”上的时间不超过30分钟。
为什么不做在线双写同步?B端核心链路一般没有现成的双写机制,像订单、库存这类强一致场景,做应用层双写等于把两个系统的代码耦合在一起,成本高还容易出隐性 bug。停机窗口虽然影响体验,但可控、可回滚,反而更稳。
1.3 数据一致性、回滚与演练
正式迁移前我准备了两层保障,缺一不可。
第一层是“切换演练”。我们在正式切换前一周,用生产数据的全量备份做了一次完整演练,包括全量迁移、增量追平、校验、回滚。演练时发现的问题,基本都被提前清掉了,正式切换时候心里就有底了。第二层是“回滚预案”。数据迁移不是迁完就行,还要考虑如果新系统上线后发现重大问题,能不能退回去。我们当时把老系统设置为“只读”模式保留了7天,而不是直接停掉。一旦新系统出现短时间内修不了的问题,可以切回老系统继续服务,只是不能写入新数据。
迁移方案的本质不是“搬运方案”,而是“保障业务连续性的方案”。
2. 迁移准备与兼容性差异排查
2.1 表结构、字段类型与字符集
迁移前我们先把老库 DDL 全部导出,和业务开发一起逐表梳理,再在达梦上跑一遍。Oracle 12c 和达梦 DM8 在 SQL 语法上兼容度很高,但细节差异仍然不少。
| Oracle 类型 | 达梦推荐类型 | 说明 |
|---|---|---|
| NUMBER(1) | INT | 布尔语义字段统一用整型 |
| NUMBER(10,0) | INT | 常规整数 |
| NUMBER(15) | BIGINT | 超过 10 位整数建议用 BIGINT |
| NUMBER(18,2) | DECIMAL(38,6) | 金额类字段保留足够精度 |
| NUMBER(38) | DECIMAL(38) | 注意达梦 DECIMAL 精度上限,超长建议用 VARCHAR 存储 |
| VARCHAR2(4000) | VARCHAR(4000) | 有中文时要注意按字符还是按字节定义 |
| BLOB / CLOB | BLOB / CLOB | 迁移时需单独处理,默认配置容易出问题 |
| DATE | TIMESTAMP | 达梦推荐使用 TIMESTAMP 避免精度丢失 |
字符集方面,老库是AL32UTF8,新库我们统一约定用 UTF-8,客户端连接参数里也强制指定 UTF-8。这个不提前处理好,导进去的中文很容易变成“口口口”。而且字符集问题往往发生在连接层,工具不报错,数据悄悄烂掉,所以必须提前锁定。
2.2 SQL 语句与函数习惯差异
迁移过程中最隐蔽的难点,其实是业务流程里那几百条 SQL 没改干净。比如分页,老系统用 Oracle 经典的ROWNUM方式:
SELECT * FROM (SELECT t.*, ROWNUM rn FROM USER_ORDER t WHERE STATUS = '0') WHERE rn BETWEEN 1 AND 20;达梦支持LIMIT,可以直接改成:
SELECT * FROM USER_ORDER WHERE STATUS = '0' LIMIT 20;如果你只是简单搬库不动应用,这个差异无所谓。但只要新系统还带着老代码做二次开发,这类 SQL 就是隐藏坑。建议迁移前全局搜一遍ROWNUM、SYSDATE、NVL、DECODE等写法,光排查就要花不少时间。
函数方面我也整理过一张对照表:
| Oracle 写法 | 达梦推荐写法 | 说明 |
|---|---|---|
| SYSDATE | NOW() 或 CURRENT_TIMESTAMP | 语义基本一致,格式化输出不同 |
| NVL(a, b) | NVL(a, b) / COALESCE(a, b) | 达梦兼容 NVL,复杂表达式建议用 COALESCE |
| DECODE(a, b, c) | CASE WHEN a = b THEN c END | 迁移时建议统一改成 CASE 结构 |
| TO_CHAR(d, 'YYYY-MM-DD HH24:MI:SS') | TO_CHAR(d, 'YYYY-MM-DD HH24:MI:SS') | 基础格式通用,部分格式修饰符 FM 有差异 |
| SEQUENCE.NEXTVAL | NEXT VALUE FOR sequence | 序列对象需要单独创建 |
2.3 主键、自增列与外键约束
老系统很多表靠序列生成主键。新系统如果用自增列,要注意“历史数据已有主键”的冲突。我们当时用的是达梦序列 + 默认值方案,迁移后先把序列的起始值设置为老数据最大主键 + 1,再开启应用写入,这样不会撞主键。
外键约束也是重灾区。如果全量导入时按原表结构建了外键,导入顺序不对就直接报主键冲突。我们全量导入时统一先禁用外键约束,数据导入完成后再逐个启用校验,能省非常多时间。不过要记住,启用外键之前一定要跑一遍完整数据校验,否则后面查问题更难。
3. 全量迁移、增量追平与停机切换实操
3.1 全量迁移:工具选择与批量优化
全量迁移我们用了达梦自带的数据迁移工具 DTS,图形界面连上 Oracle,选择目标库后它能自动识别表结构和大部分数据类型,生成迁移脚本。小表直接迁移,大表建议用命令行工具dmfldr做批量导入,速度差别非常大。
印象最深的是批量提交参数。默认情况下 JDBC 提交频率比较保守,一次性提交几千条没问题,但碰到几十万行的流水表就会很慢。实测下来,把批量提交大小调到 5000 到 10000,并且使用预编译语句,迁移速度能提升 5 倍左右。
表结构迁移完之后,先别着急导数据。应先建“基本索引 + 主键”,但大表的二级索引等数据导完再建。因为导入过程中每插入一条都要维护索引,代价极高,数据导完再统一创建索引,编译一遍反而更快。
3.2 增量追平:数据同步点位设计
增量追平是整套方案里最需要接住业务细节的地方。每一张需要同步的表,都要判断能用什么条件做增量:
- 表里有
CREATE_TIME/MODIFY_TIME时间戳,直接按时间过滤 - 没有时间戳但有递增主键,按最大 ID 作为同步点位
- 只有“插入”没有“更新”的流水表,最简单
- 既有插入又有更新、删除的表,必须额外处理。我当时就用了一张
CHANGE_LOG表,由触发器在 Oracle 端记录变动的主键和操作类型,增量同步程序读这张表做增删改
增量任务我们设置的是每 15 分钟跑一次。每次跑之前先检查上次的同步状态,比如LAST_SYNC_TIME、LAST_MAX_ID,跑完把最新点位更新回去。这里容易踩的坑是:如果你自己手写同步逻辑,一定要把“同步点位更新”和“数据写入”放在同一个事务里。否则同步中途挂了,重启后会重复拉同一批数据,导致主键冲突或重复数据。
3.3 停机切换当天的时间线
我们的正式切换从周五晚高峰结束后开始,安排如下:
- 23:30 老系统应用入口进入维护页,禁止用户发起新写入交易
- 23:35 停掉老系统所有后台任务、定时批处理
- 23:40 执行最后一次增量追平,追平窗口约 15 分钟
- 00:00 开始做关键表行数校验、金额汇总校验、唯一性校验
- 00:30 新系统正式启动,开放内部白名单用户验证
- 01:00 核心业务验证通过,切换入口流量
每个时间节点的操作都在迁移手册里提前写清楚,负责人一目了然。切换当天一定不要即兴发挥,所有命令行、数据库连接字符串、校验 SQL 都要提前准备好,到时只是执行确认动作。
3.4 重点表数据的校验方法
校验是迁移的重中之重。光看日志“迁移成功”没有意义,必须做数据级验证。我用三个方法交叉确认:
第一是行数比对,老库新库逐张表SELECT COUNT(*),要求完全一致。
第二是金额类汇总,比如订单表、流水表,对关键字段做SUM(金额)或SUM(ABS(字段))对比,防止行数一致但内容错位。
第三是抽样比对。我写了一个抽样工具,从老库随机抽取若干条记录,用多个字段拼业务主键后到新库回查,比对关键字段是否一致。尤其是那些没有时间戳但业务含义很重要的描述性字段,靠抽样最容易发现问题。校验结果要保留审计记录,方便后续追溯。
4. 新老系统切换中的典型问题与排查实录
4.1 问题速查表
迁移过程中遇到不少问题,把典型问题整理成一张速查表,基本都是直接用得上的经验。
| 现象 | 根因 | 解决方式 |
|---|---|---|
| 导入后中文乱码 | 客户端字符集与数据库字符集不一致 | 统一 UTF-8,连接参数指定字符集后重新导入 |
| BLOB/CLOB 数据丢失或损坏 | 工具默认对 LOB 处理不彻底 | 使用 DTS 指定 LOB 处理策略,或分表单独迁移 |
| 主键冲突 | 序列起始值设置不对 | 迁移后执行 ALTER SEQUENCE 校准起始值 |
| 外键校验失败 | 全量导入时未禁用约束 | 先禁用约束导数,再逐个启用 |
| 大批量导入慢 | JDBC 批次设置不合理 | 调整批量提交大小,关闭自动提交,预编译 SQL |
| 达梦建索引失败 | 字段类型或长度超限 | 检查源字段映射定义,长度按字符数重新定义 |
| 存储过程报错 | Oracle 语法细节与 DM 不兼容 | 逐个编译排查,重点检查动态 SQL 中的函数写法 |
| 增量同步重复数据 | 同步点位和写入不在同一事务 | 将更新点位与写入放在同一事务中 |
| 时间数据错位 | 老库带时区,新库使用无时区 TIMESTAMP | 统一使用客户端时区转换,或改用带时区类型 |
4.2 最典型的三类坑
中文乱码是我这次遇到的第一个坑。一开始用 DTS 迁移时,看着导入进度正常,但随机抽查发现部分描述字段变成了乱码。排查到最后发现,问题不是工具,而是客户端环境变量里的NLS_LANG没有设置成 UTF-8,连接用的还是旧数据库字符集。这个很隐蔽,因为错误发生在连接层,不是数据层,工具不会报任何异常。
大字段迁移是第二个重灾区。BLOB 存图片、附件、合同文件,量一大就麻烦。DTS 对 LOB 字段在默认配置下可能会分批读取失败,导致个别记录丢失。解决办法是把含 LOB 的表拆出来,用 DTS 的“仅结构”先迁移,数据再用dmfldr单独导入,并且导入完做一次字段级别抽样比对。
第三个是自增序列。老系统用 Oracle 的SEQUENCE生成主键,历史数据主键已经排到 100 万。迁到新库后,如果直接把序列起点设成 1,新插入数据立刻撞主键。迁移完需要执行一条类似ALTER SEQUENCE seq_user_order RESTART WITH 1000001的调整语句,给每条序列按照对应表的最大值重新校准,这类问题才会被根除。
4.3 增量同步中的隐蔽问题
增量同步还有一个容易忽略的场景:老系统中存在定时任务批量 UPDATE 数据,比如每天凌晨统一更新订单状态。如果同步任务恰好跨过这个时间点,而表的增量字段用的是更新时间,可能会有漏项或者重复。我们当时的处理是,在增量同步 SQL 里设置一个“重叠窗口”:每次查询条件往前多退 5 分钟,拉到的数据先根据主键去重再写入,能有效避免边界问题。
另外,增量追平阶段我不建议直接用MERGE或者UPSERT一把梭,因为 B 端核心表通常有审计字段、版本号之类的逻辑,直接覆盖容易造成数据丢失。更稳的做法是先记录到一张同步临时表,再由业务方确认更新逻辑后统一应用。
5. 切换完成后的验证与灰度放量
5.1 上线初期的双轨监控
正式切换完成之后,不代表数据迁移工作就结束了。我在切换后的第一个业务周期内保持“双轨监控”:老系统保留只读入口,新系统记录所有关键操作的审计日志。两个系统同时能看到同一份数据源,让业务同学在新老页面各查一遍,核对计算结果是否一致。
这种双轨监控不要持续时间过长,一般 3 到 7 天即可。时间太长,团队会疲于在两个系统间来回核对,而且老系统数据不再增加,比对的意义会越来越小。
5.2 灰度放量与回滚开关
对于重要系统,我会再加一层灰度放量。先让某个事业部、某个仓库或某个客户群使用新系统,观察数据有没有异常,没异常再逐步放量。放量粒度要小,最好能通过配置开关动态调整,而不是发版改代码。
回滚开关也需要提前埋好。我们的做法是:新系统所有写操作都要走一层抽象接口,一旦出现严重问题,应用层可以一键把写操作切换到“拒绝/记录”模式,业务链路切回老系统只读页面。这种开关平时是不开启的,但必须经过演练验证,不能到关键时候发现开关失灵。
5.3 收尾工作:旧库归档和监控清理
切换稳定后,还有两个容易被忽略的收尾工作。老库不建议立刻删除,我一般保留只读状态 15 天,然后转成离线归档打包,再保存一段时间。数据迁移这件事上,老库是最后的保险绳,删早了风险极大。
新库的监控要持续观察一段时间,特别是慢查询、锁冲突、大事务这些指标。因为迁移后统计信息、执行计划可能和原来不同,原本在 Oracle 上跑得飞快的 SQL,在达梦上不一定同样快。要给新库建好索引、更新统计信息,把执行计划调优做扎实。
这次项目做完,我最大的体会是:技术工具只是数据迁移的入口,真正决定成败的是流程、校验、回滚这些看起来很笨的功夫。如果你正准备做 B 端新老系统切换,建议把迁移方案拆成可执行的步骤、可验证的口径和可回滚的预案,切换当天才会从容很多。
本文还有配套的精品资源,点击获取