migrate是Go生态最稳的数据库迁移方案,需用CLI安装并验证:Mac查GOPATH加bin到PATH,Windows推荐choco install;迁移文件须成对命名如000001_init.up.sql/.down.sql,禁用AutoMigrate上生产。

migrate 是当前 Go 生态里最稳的数据库迁移方案,不是 AutoMigrate,也不是手写 SQL 执行器。它不绑定 ORM、支持多数据库、能版本追踪、可逆执行,上线前必须用 CLI 跑通,不能靠 Go 代码“试出来”。
怎么装 migrate CLI 并验证可用
别信 go install 就完事——新版默认不加 $GOPATH/bin 到 $PATH,装完直接运行 migrate -version 很可能报 command not found。
- Mac:装完后查
go env GOPATH,把$GOPATH/bin加进 shell 配置(如~/.zshrc)再source - Windows:用
choco install migrate更省心,避免驱动名大小写(比如postgres写成Postgres)或路径权限问题 - 别用
docker run --rm -v $(pwd):/migrations migrate/migrate临时跑——挂载路径在不同系统下行为不一致,且容器内默认没装对应数据库驱动
迁移文件命名和内容怎么写才不会被跳过
migrate 对文件名极其敏感:漏掉 .up.sql 后缀、大小写错、多加空格,都会导致静默跳过,表根本不会建。
- 必须成对存在:
000001_init.up.sql和000001_init.down.sql(序号法),或20240520103000_add_users_table.up.sql(时间戳法),二者不能混用 - 用
migrate create -ext sql -dir ./migrations -seq init生成,它自动处理序号+后缀,比手写安全得多 -
.down.sql不是可选:哪怕你暂时不回滚,也得至少写DROP TABLE IF EXISTS users;,否则migrate down直接报错退出 - SQL 文件开头不要写
-- +migrate Up这类注释——migrate不识别,纯属干扰
为什么 AutoMigrate 绝对不能上生产
AutoMigrate 是结构同步工具,不是迁移工具。它不记录版本、不生成 down、不保证幂等,上线等于裸奔。
立即学习“go语言免费学习笔记(深入)”;
- 模型里删了
Age int字段,数据库字段还在;下次SELECT *查出来nil,Go 层直接 panic - 多个服务实例同时启动,可能并发执行
AutoMigrate,触发 PostgreSQL 的relation already exists错误 - 它不生成任何 SQL 日志,出问题只能翻源码猜;也不支持跨大版本变更(比如把
user表拆成users+profiles) - 如果非要用,至少包一层检查:
if !db.Migrator().HasTable(&User{}) { db.AutoMigrate(&User{}) },但仅限本地开发
生产环境跑迁移前必须做的三件事
DDL 不是万能的,事务也不能兜底。MySQL 的 ALTER TABLE DROP COLUMN 会锁表,SQLite 的 ALTER TABLE 甚至不能回滚。靠工具不如靠人盯。
- 先在同版本数据库上手动执行:
psql -f 20240520103000_add_users_table.up.sql,尤其注意 MySQL 的ONLY_FULL_GROUP_BY模式会不会让迁移失败 - 跑
migrate -path ./migrations -database "your-url" version确认当前版本,避免误up或重复执行 - 执行前加超时控制:CLI 默认无超时,长迁移卡住会导致 CI/CD 流水线挂起;Go SDK 中要传
context.WithTimeout(..., 30*time.Second),失败就log.Fatal,别静默跳过
真正难的从来不是命令怎么敲,而是 .up.sql 里那几行 ALTER 是否考虑了数据迁移、外键约束、索引重建,以及 .down.sql 是否真能撤回——这些没法靠工具推导,得人一条条想清楚、测清楚。


















