migrate cli是go生态数据库迁移的唯一稳妥路径,因其纯sql文件驱动、严格命名规则、独立执行不依赖go运行时,可避免schema_migrations表与实际结构脱节。

必须用 migrate CLI 工具管理迁移,自己拼 SQL 执行顺序 90% 会导致 schema_migrations 表与实际结构脱节。
为什么 migrate CLI 是唯一稳妥路径
Go 生态没有内置迁移框架,migrate 不是“可选工具”,而是避免线上 schema 不一致的事实标准。它靠纯 SQL 文件 + 严格命名 + 独立 CLI 驱动,不依赖 Go 运行时状态,回滚可靠、版本可追溯。
常见错误现象:
- 手写
db.Exec("CREATE TABLE...")多次后,某次失败但schema_migrations未写入 → 下次up认为已执行,跳过建表 - 多个服务实例并发调用同一段迁移代码 →
schema_migrations表被多线程竞争写入,版本记录错乱 - 测试环境跑通,生产环境因事务限制(如 PostgreSQL DDL 不允许在函数内执行)直接 panic
这些都不是 bug,是绕开 CLI 自行封装导致的设计盲区。
migrate create 生成文件时必须用 -seq 或 -ts,不能手写命名
命名不合规会导致静默跳过 —— 它不报错,也不执行,只当没看见文件。
- 正确格式:
000001_init.up.sql+000001_init.down.sql(序号 64 位整数,不能跳、不能重复) - 推荐命令:
migrate create -ext sql -dir ./migrations -seq init(自动生成递增序号) - 别混用:
20240501_init.up.sql和000002_add_index.up.sql一起放目录里 → 排序逻辑崩坏,执行顺序不可控 -
.down.sql不可省略:哪怕内容为空或只写DROP TABLE IF EXISTS users;,否则migrate down直接失败
PostgreSQL 连接 URL 必须带 ?sslmode=disable,密码含 @ 或 / 要转义
连接失败十有八九不是网络问题,而是 URL 解析失败。
- 错误示例:
postgres://user:p@ss/word@localhost/db→ 解析器把p@ss/word当成 host,截断后连不到库 - 正确做法:用
url.QueryEscape("p@ss/word")得到p%40ss%2Fword,再拼进 URL - 驱动名大小写敏感:
postgres可以,Postgres或PG会报unknown driver "Postgres" - MySQL 同理:必须加
?parseTime=true,否则时间类型解析失败
生产上线前必须跑 migrate validate 和 migrate version
这两个命令不改数据,但能提前暴露绝大多数部署事故。
-
migrate validate:校验所有.up.sql和.down.sql是否语法合法、是否成对、是否编号冲突 -
migrate -database "..." -path "./migrations" version:确认当前 DB 版本号,避免误up或漏up - 别跳过这步:曾有团队在 CI 里漏掉
validate,上线时发现某.down.sql里少了个分号,导致down 1直接卡死,人工修复耗时 40 分钟
最易被忽略的是:迁移文件一旦提交 Git,就不能再修改内容(尤其是已上线的),只能追加新迁移。改旧文件等于重写历史,各环境版本会彻底失联。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











