Go无内置迁移工具,需用migrate或gormigrate;migrate以时间戳命名SQL文件管理版本,支持多环境部署;GORM的AutoMigrate不记录版本、不保证幂等,上线禁用;DDL事务支持因数据库而异,生产前须手动验证SQL。

Go 里没有内置 migration 工具
Go 标准库 database/sql 只负责执行 SQL,不提供版本化迁移能力。你得靠第三方库,主流就两个:migrate(golang-migrate/migrate)和 gormigrate(GORM 生态专用)。别自己手写迁移逻辑——哪怕只有三张表,加个字段顺序错、回滚没写、环境变量漏配,第二天就线上报 column not found。
用 migrate 做 CLI 迁移最稳
它把迁移文件当“不可变快照”管理,靠文件名排序执行,不依赖 Go 代码里的函数调用顺序。适合 CI/CD 和多环境部署。
- 迁移文件必须按
YYYYMMDDHHMMSS_XXX.up.sql和.down.sql命名,比如20240520103000_add_users_table.up.sql - 数据库 URL 通过
-database参数传,别硬编码;SQLite 路径要写绝对路径,否则migrate在不同工作目录下找不见.db文件 - 执行迁移前先
migrate -path ./migrations -database "postgres://..." version看当前版本,避免误跑重复 up -
up是默认动作,但down不会自动 rollback 到上一版——得显式指定步数,比如migrate -path ... down 1
GORM 用户慎用 AutoMigrate
AutoMigrate 会直接改表结构,不记录版本、不生成 down 脚本、不保证幂等。开发阶段图快可以,但上线后等于裸奔。
- 它不会删字段或索引,只增不减;如果模型里删了
Age int,数据库里字段还在,下次查SELECT *就 panic - 多个服务实例同时启动时,可能并发执行
AutoMigrate,触发 PostgreSQL 的relation already exists错误 - 想用它做迁移?至少包一层检查:
if !db.Migrator().HasTable(&User{}) { db.AutoMigrate(&User{}) }
迁移失败时,事务不是万能的
PostgreSQL 支持 DDL 在事务里执行,MySQL 8.0+ 部分支持,但 SQLite 的 ALTER TABLE 仍不能回滚。别假设 .down.sql 一定能撤回所有变更。
立即学习“go语言免费学习笔记(深入)”;
- 涉及重命名表、拆分字段、转换数据类型的操作,优先在
.up.sql里用临时表 + 数据迁移 + 重命名三步走,而不是单条ALTER TABLE ... RENAME COLUMN -
migrate默认不开启事务执行单个迁移文件;如需强一致性,得在 SQL 文件开头加BEGIN;,结尾加COMMIT;或ROLLBACK;,但它不帮你校验语法 - 生产环境跑迁移前,务必在同版本数据库上先
psql -f xxx.up.sql手动试一遍,尤其注意 MySQL 的ONLY_FULL_GROUP_BY模式会不会让迁移 SQL 报错


















