Golang migrate 做数据库变更管理

最近在使用 golang-migrate 做数据库变更管理,按照官方的教程,需要本地 先下载一个二进制,命令行生成变更文件:

$ migrate create -ext sql -dir db/migrations -seq create_article_table
...项目路径/db/migrations/000011_create_article_table.up.sql
...项目路径/db/migrations/000011_create_article_table.down.sql
./db/migrations.sql000011000001create_article_table.up.sql.down.sql

我们在编辑完之后,可以这样在本地变更数据库:

$ export POSTGRESQL_URL='postgres://postgres:密码@localhost:5432/dbname?sslmode=disable'
$ migrate -database ${POSTGRESQL_URL} -path db/migrations up
no change

但是在实际使用中,我们在发布项目之后,如果每次都还要去线上变更一下,那就比较麻烦了,能不能让代码自己来运行呢? 当然可以。

代码自动执行变更

sourceiofsgithubgitlabs3
embediofs
package main

import (
    "context"
    "embed"
    "time"

    _ "github.com/golang-migrate/migrate/v4/database/postgres"
    "github.com/sirupsen/logrus"
)

var (
    //go:embed db/migrations/*.sql
    fs embed.FS
)

func initDB(config *Config) {
    var err error
    uri := fmt.Sprintf(
        "postgres://%s:%s@%s:%s/%s?sslmode=disable",
        config.DBUser, config.DBPassword, config.DBHost, config.DBPort, config.DBName,
    )
    ctx := context.Background()
    db, err = pgxpool.Connect(ctx, uri)
    if err != nil {
        logrus.Fatalf("connect to db failed: %v", err)
    }

    if err = db.Ping(ctx); err != nil {
        logrus.Fatalf("could not connect to database: %v", err)
    }

    d, err := iofs.New(fs, "db/migrations")
    if err != nil {
        logrus.Fatalf("could not open migrations: %v", err)
    }
    m, err := migrate.NewWithSourceInstance("iofs", d, uri)
    if err != nil {
        logrus.Fatalf("could not init migrate: %v", err)
    }
    err = m.Up()
    if err != nil {
        logrus.Errorf("migrate up error: %v", err)
    }
}

func main() {
    config := GetConfig()
    initDB(config)
}
var fs embed.FSfs

这样就可以在每次启动之后,自动先做数据库变更然后才开始执行代码了。但是有一点值得注意,跑数据库变更的程序,最好只部署 一份,否则容易出现竞争问题。

总结

这篇文章记录了我使用migrate的方式,这种方式比所有操作都在命令行执行更加方便,也不再需要将sql文件同步到服务器,当然 缺点就是二进制文件会变的更大一些。有利有弊,不过我更倾向于这种方式。


更多文章