最近在使用 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文件同步到服务器,当然 缺点就是二进制文件会变的更大一些。有利有弊,不过我更倾向于这种方式。