去年底老板拍板:核心交易系统去 Oracle。理由很直接——一年 380 万的授权费,加上审计合规越来越严。我接手时第一反应是:这活儿坑比想象多,不是导出 SQL 再导入就完事。
先盘家底
系统跑了九年,Oracle 里不止 SQL。我用了两周做依赖盘点,列了一张表:
| 依赖类型 | 数量 | 风险 |
|---|---|---|
| 存储过程/函数 | 213 个 | 高,逻辑重 |
| 触发器 | 41 个 | 中,行为隐式 |
| 序列(Sequence) | 67 个 | 低,有替代 |
| 自定义类型/包 | 28 个 | 高,无直接对应 |
| DBLink 跨库查询 | 9 个 | 中,需改架构 |
真正难的是那 213 个存储过程和 28 个包,里面有大量业务规则。直接翻译到 MySQL 语法只是第一步,逻辑正确性才是雷区。
兼容性改造:分层拆解
我们没有一把梭全改,而是按"能不能挪到应用层"分层:
- 能上移的:把 60% 的存储过程逻辑改成 Java 服务里的 Spring 事务方法,用
@Transactional保证一致性; - 必须下沉的:剩余涉及多表批量计算的,用 MySQL 的存储过程重写,但把隐式游标改成显式
CURSOR,并补上异常处理; - 触发器:能删的删,不能删的用 Binlog + 下游消费者替代,避免触发器带来的写入放大。
一个典型的 Oracle 分页 ROWNUM 写法:
-- Oracle
SELECT * FROM (SELECT t.*, ROWNUM rn FROM orders t WHERE ...) WHERE rn BETWEEN 21 AND 40;
-- 改 MySQL
SELECT * FROM orders WHERE ... ORDER BY id LIMIT 20 OFFSET 20;
看起来简单,但 ROWNUM 带排序语义的查询,翻译错一次就会分页漏数据。
数据迁移:全量加增量
全量用自研的批导工具,按主键分片并发,单表 8000 万行跑了 6 小时。增量用 Oracle GoldenGate 同步到 MySQL,追平延迟控制在 3 秒内。迁移期间双库同时写,靠应用层双写开关控制。这里最怕的是两边"写后读不一致"——我们在关键读路径加了"以 Oracle 为准"的开关,灰度期全走老库。
双跑验证
上线前做了 30 天双跑:同样一笔请求,应用层同时打 Oracle 和 MySQL,用对账 Job 比结果。初期每天差 300+ 笔,逐一定位,大多是浮点四舍五入、NVL 与 IFNULL 的空值语义差异。修到连续 7 天差异为 0,才敢动切换预案。
切换预案:不成功就回滚
切换按"读流量 → 非核心写 → 核心写"三步走,全程可回滚:
- 读流量切到 MySQL,观察 24 小时,监控错误率和延迟;
- 非核心写(日志、统计)切 MySQL,保留 Oracle 双写为兜底;
- 核心写切换当晚,停 Oracle 写入、保留只读 7 天,确认无误后下线。
真正切核心写那晚,我们准备了 15 分钟回滚窗口:一旦 MySQL 主库报错率超 0.5%,立刻把写开关拨回 Oracle。结果是平稳的,P99 延迟反而从 Oracle 的 23ms 降到 14ms。
组织协同比技术更难
技术之外,去 O 真正的阻力在协作。DBA、业务、测试三方对"双跑差异"的容忍度不同:DBA 要 0 差异才肯切,业务怕影响交易,测试只认自己的用例。我们每周开一次对齐会,把当日差异清单逐条过,明确"哪些差异可解释、哪些必须修"。有次一个浮点差异 DBA 坚持要修,业务说不影响,最后我们加了一层"金额精度统一到分"的兜底转换,两边都签字。这种跨团队的"差异仲裁机制"比任何技术方案都重要——没有它,双跑会无限期拖下去。
留个问题
关于《一次核心系统去 Oracle 化的完整过程》里这个坑,你当时是怎么处理的?欢迎在评论区聊聊你踩过的类似情况。