MySQL 8.0 迁移到云数据库那晚,我亲手把 127.0.0.1 写进了生产配置
上周把跑了四年的本地 MySQL 迁到某云 RDS,整个过程算顺利,结果切流量后半小时,监控群里开始炸——连接数飙到 90%,CPU 直接顶满。排查了四十分钟才发现,有个老模块的配置文件里硬编码了 127.0.0.1:3306,迁库后没改,它就在那疯狂重连、疯狂报错、疯狂占连接池。
这事给我上了一课:数据迁移不是导完 SQL 就完事,是得把整个"调用链"重新审计一遍。 下面说几个我这次踩实了的坑,都是血泪换来的。
一、建表阶段:字符集和排序规则别"随库默认"
云厂商给的 MySQL 8.0 实例,默认字符集可能是 utf8mb4_0900_ai_ci,但我老库是 utf8mb4_unicode_ci。直接导过去不报错,等联调时才发现:两张表 JOIN 的时候,排序规则不一致直接抛错。更隐蔽的是,有些云数据库的 lower_case_table_names 参数和你本地不一样,本地 Windows 开发是 1(不区分大小写),Linux 生产是 0,迁完一跑,"Table doesn't exist" 看得我头皮发麻。
我的做法现在变成:迁之前先 SHOW VARIABLES LIKE '%case%'、SHOW VARIABLES LIKE 'character%',把差异列一张对照表,建库脚本里全部显式指定,绝不依赖默认。
二、升级场景:DATETIME 默认值和 sql_mode 的暗箭
MySQL 5.7 迁 8.0 有个经典坑:老表里一堆 DATETIME DEFAULT '0000-00-00 00:00:00',5.7 能跑,8.0 默认 sql_mode 含 NO_ZERO_DATE,导数据时直接中断。我那次是半夜操作,没开严格模式测试,生产一导就挂。
还有更阴的:某个插件表用了 GROUP BY 但不完整,5.7 里 ONLY_FULL_GROUP_BY 没开,8.0 默认开启,迁完业务逻辑直接崩。建议升级前先拿 pt-upgrade 或者云厂商的兼容性评估工具跑一遍慢查询,别信"8.0 完全兼容"这种鬼话。
三、卸载/回滚:你以为删了,其实没删干净
这次迁移我做过一次回滚演练,发现个很脏的问题:云 RDS 卸载后,应用服务器的连接池还在发请求。Druid、HikariCP 这类池子,如果配置了 testWhileIdle 或者 validationQuery,老连接不会立即感知数据库下线,而是等到超时或者检测周期才暴露。表象就是"数据库都删了,怎么还有连接在尝试访问"。
另外,CDN 和 OSS 的自定义域名如果绑了 CNAME 到数据库相关的分析服务(比如某些日志归档),主库一迁,那些边缘配置没人记得,过半个月账单里冒出异常流量才反应过来。
四、我现在用的笨办法:一份"迁移后必查清单"
1. 全局搜代码库里所有 127.0.0.1、localhost、旧内网 IP、旧域名——别信配置文件命名,有人会把测试配置叫 prod.db.ini;
2. 导完数据后,随机抽 10 张表,对比行数、checksum、自增 ID 当前值;
3. 用 SHOW PROCESSLIST 观察十分钟,看有没有异常来源 IP 或睡眠连接堆积;
4. 回滚脚本和回滚脚本测试,必须提前写好,别等出事了现编。
那次 127.0.0.1 的锅,最后是重启应用解决的——因为连接池里的脏连接只有重启才彻底释放。用户在群里骂了二十分钟,我在屏幕前盯着重启进度条,手都是凉的。
你们迁移数据库时,有没有遇到过"表面成功、暗处埋雷"的情况?

