Go 数据库迁移实战:用 golang-migrate 做版本化、可回滚的表结构演进

test12026-10-121 次阅读

为什么不用代码里自动建表

手写 CREATE TABLE 散落在初始化函数里,既看不到历史,也回不去。golang-migrate 把每次结构变更写成一对 up/down SQL 文件,带递增版本号,向上迁移和向下回滚都有据可查。

编写迁移文件

文件名格式为 {版本}_{名称}.up.sql 与 .down.sql。例如新增 users 表:

-- 000001_create_users.up.sql
CREATE TABLE users (
  id BIGSERIAL PRIMARY KEY,
  email VARCHAR(255) NOT NULL UNIQUE,
  name VARCHAR(120) NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- 000001_create_users.down.sql
DROP TABLE IF EXISTS users;

在程序启动时执行迁移

用 migrate 库驱动,支持 file:// 与数据库直连。下面用 Go 代码在启动期把数据库拉到最新版本。

package main

import (
	"flag"
	"log"

	"github.com/golang-migrate/migrate/v4"
	_ "github.com/golang-migrate/migrate/v4/database/postgres"
	_ "github.com/golang-migrate/migrate/v4/source/file"
)

func main() {
	dsn := flag.String("db", "postgres://app:pass@localhost:5432/app?sslmode=disable", "数据库连接")
	flag.Parse()

	m, err := migrate.New(
		"file://db/migrations",
		*dsn,
	)
	if err != nil {
		log.Fatalf("migrate new: %v", err)
	}
	if err := m.Up(); err != nil && err != migrate.ErrNoChange {
		log.Fatalf("migrate up: %v", err)
	}
	log.Println("数据库迁移完成")
}

回滚与版本管理

  • 开发期用 m.Steps(-1) 回退一步,生产环境回滚要谨慎,建议和代码版本一起走发布流程。
  • 迁移文件一旦合入主干不要修改,需要变更就新增更高版本号的文件,保证多环境一致。
  • CI 里加一步 migrate up 到测试库,提前暴露 SQL 语法和约束冲突。
  • 大表加字段尽量用 ALTER TABLE ... ADD COLUMN 配合默认值或后台批量回填,避免长锁。
T

test1

文章作者

为什么不用代码里自动建表 手写 CREATE TABLE 散落在初始化函数里,既看不到历史,也回不去。golang-m...

分类
技术
发布时间
2026-10-12
字数
约 1272 字
阅读
1 次