生产环境数据库迁移禁用gorm automigrate,必须使用migrate cli配合显式版本文件;需带-seq参数生成配对up/down文件,postgresql连接url须含?sslmode=disable,代码中调用migrate.up时要关闭事务包装、设连接池为1并独占db实例。

别用 GORM AutoMigrate 做生产环境数据库变更——它不记录过程、无法回滚、字段重命名可能删数据。 真正可控的迁移必须基于显式版本文件 + 顺序执行引擎,migrate CLI 是当前 Go 生态唯一被广泛验证的落地方案。
为什么 migrate create 必须带 -seq 参数
手动生成迁移文件名(比如 000002_add_index.up.sql)极易出错:序号跳变、重复、漏掉 .down.sql 都会导致 migrate up 静默跳过或 migrate down 直接 panic。而 migrate create -ext sql -dir ./migrations -seq add_index 会自动创建一对严格配对的文件:
000001_add_index.up.sql000001_add_index.down.sql
序号由工具自增管理,避免人工干预;.down.sql 即使内容为空(只写 -- noop),也必须存在,否则 down 命令报 no down migration found。
PostgreSQL 连接 URL 必须加 ?sslmode=disable
错误现象:migrate up 报 unknown driver "postgres" 或直接 panic,不是驱动没装,而是 URL 解析失败。
正确写法示例:
postgres://user:pass@localhost:5432/mydb?sslmode=disable
关键点:
- 必须带
?sslmode=disable,否则 lib/pq 拒绝连接(尤其本地开发和 CI) - 密码含
@或/时,必须先用url.QueryEscape处理,否则解析截断成错误 host - 驱动名小写:用
postgres,不用Postgres或PG
Go 代码中调用 migrate.Up 的三个硬约束
在服务启动时嵌入迁移(如 main() 中调用),最容易崩在 PostgreSQL 上,报错:ERROR: CREATE TABLE cannot be executed from a function。
这不是 bug,是 PostgreSQL 对 DDL 在函数/事务内执行的限制。解决办法只有三条:
- 迁移前关闭事务包装(
migrate.WithInstance传入非事务连接) - 连接池最大数设为 1(避免并发迁移冲突)
- 迁移完成后立即关闭该
*migrate.Migrate实例,绝不复用到业务 DB 句柄
别试图在同一个 *sql.DB 上既跑迁移又跑业务查询——DDL 和 DML 混用在 PG 里天然不安全。
up/down 脚本里不能依赖事务自动提交
MySQL 默认自动提交,但 PostgreSQL 的 CREATE TABLE 等 DDL 语句本身隐式提交事务,所以你在 .up.sql 里写多条语句,中间任何一条失败,前面的已生效,无法整体回滚。
这意味着:
-
.down.sql必须能独立处理“部分成功”状态(比如加了索引但没改字段,DROP INDEX IF EXISTS要兜底) - 涉及数据迁移(如 copy+rename 字段)的逻辑,必须拆成两个迁移文件:先加新字段、再移除旧字段,而不是塞进一个
.up.sql - 别在 SQL 迁移里写条件判断(如
IF NOT EXISTS不够用时),Go 函数迁移虽支持,但会增加部署复杂度,慎选
最常被忽略的一点:迁移不是“一次写完就结束”,而是每次上线前都要在预发环境跑一遍 migrate down && migrate up,验证可逆性——90% 的线上事故,源于 down 脚本压根没测试过。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











