必须用migrate CLI而非手写db.Exec,因其纯SQL驱动、严格命名、独立执行,可避免schema_migrations表与实际结构脱节;手写易致并发写入错乱、事务内DDL报错、失败后静默跳过等线上高发问题。

直接用 migrate CLI 工具管理迁移,别在 Go 代码里自己拼 db.Exec —— 90% 的线上 schema 不一致问题都源于绕过 CLI 自行封装。
为什么必须用 migrate CLI 而不是手写迁移逻辑
Go 生态没有像 Rails 或 Django 那样内置迁移框架。migrate 不是“可选工具”,而是避免生产环境 schema_migrations 表与实际结构脱节的事实标准。它靠纯 SQL 文件 + 严格命名 + 独立 CLI 驱动,不依赖 Go 运行时状态。
- 手写
db.Exec("CREATE TABLE ...")多次后某次失败 →schema_migrations没写入 → 下次Up()认为已执行,跳过建表 - 多个服务实例并发调用同一段迁移代码 →
schema_migrations表被竞争写入,版本记录错乱 - PostgreSQL DDL(如
CREATE TABLE)在事务块里会报ERROR: CREATE TABLE cannot be executed from a function,而 SDK 默认为每个 SQL 启事务
migrate create 生成文件的硬性规则
命名不合规会导致静默跳过:它不报错,也不执行,只当没看见文件。
- 必须用
-seq或-ts生成,不能手写序号:migrate create -ext sql -dir ./migrations -seq init - 正确格式:
000001_init.up.sql+000001_init.down.sql(64 位整数前缀,不能跳、不能重复) - 禁止混用命名风格:比如把
20240501_init.up.sql和000002_add_index.up.sql放一起 → 排序逻辑崩坏,执行顺序不可控 -
.down.sql不可省略,哪怕内容只是DROP TABLE IF EXISTS users;,否则migrate down直接失败
PostgreSQL / MySQL 连接 URL 容易踩的坑
连接失败十有八九不是网络问题,而是 URL 解析失败。
- PostgreSQL:DSN 必须以
postgres://开头(不是postgresql://),且必须带?sslmode=disable(开发/测试环境)或?sslmode=require(生产) - MySQL:必须加
?parseTime=true,否则时间类型解析失败;密码含@或/时要先用url.QueryEscape编码,例如p@ss/word→p%40ss%2Fword - 驱动名大小写敏感:
postgres可以,Postgres或PG会报unknown driver "Postgres"
上线前必须跑的两个验证命令
这两个命令不改数据,但能提前暴露绝大多数部署事故。
-
migrate validate:校验所有.up.sql和.down.sql是否语法合法、是否成对、是否编号冲突 -
migrate -database "postgres://..." -path "./migrations" version:确认当前 DB 版本号,避免误up或漏up
曾有团队在 CI 里漏掉 validate,上线时才发现某个 .down.sql 里写了非法语法,回滚路径直接失效。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











