1. gopg-migrations 是什么?
gopg-migrations 在我们使用数据库时,每次发布都要改一些表结构,或者修改数据之类的操作。
这些操作,手动执行既危险,又容易忘记;当新人看到奇怪的表结构,感觉到很诧异。如果我们能将所有操作管理起来,本地测试好之后再发布上去,那么就不会有上述这些问题。
因此,gopg-migrations 这个库,给我们带来非常大的便利。当然,这里是对 postgres 数据库的支持。
2. 怎么使用
下载扩展库 github.com/go-pg/migrations/v7
即可使用。
2.1 假如我们先创建一个数据库 students,然后调用 migrations 去执行代码。
步骤如下:
编写创建表的 sql,使用 migrations 目录管理起来,num_xxx 表示按照 num 顺序执行 主逻辑 main.go 主逻辑如下:
package mainimport ("fmt""time"pg "github.com/test_go_pg/pg""go.uber.org/zap"
)func main() {fmt.Println("Starting go-pg-migrations...")// Bootstrap check pgif err := pg.PGDBWrite.Ping(); err != nil {fmt.Println(pg.DBWriteConnectionError, zap.Error(err))return}fmt.Println("PostgreSQL is running",zap.String("user", pg.PGDBWrite.Options().User),zap.String("addr", pg.PGDBWrite.Options().Addr),zap.String("db", pg.PGDBWrite.Options().Database))// Migrate to latest pg schemaif err := pg.PGDBWrite.Migrate(); err != nil {fmt.Println(pg.DBMigrationError, zap.Error(err))return}time.Sleep(time.Hour)fmt.Println("go-pg-migrations is stopping...")
}
gopg-migrations 相关函数编码如下:
package pgimport ("context""fmt""time""github.com/go-pg/migrations/v7""github.com/go-pg/pg/v9""go.uber.org/zap"
)type TGPGDB struct {*pg.DB
}func NewTGPGDB(db *pg.DB) *TGPGDB {return &TGPGDB{db}
}type TGPGDBOptions struct {Url stringDisableBeforeQueryLog boolDisableAfterQueryLog bool
}func CreateTGPGDB(url string) *TGPGDB {return CreateTGPGDBWithOptions(&TGPGDBOptions{Url: url})
}func CreateTGPGDBWithOptions(dbOpts *TGPGDBOptions) *TGPGDB {opts, err := pg.ParseURL(dbOpts.Url)if err != nil {fmt.Println(DBURLParseError, zap.String("URL", dbOpts.Url), zap.Error(err))return nil}opts.ReadTimeout = DBReadTimeoutopts.WriteTimeout = DBWriteTimeoutopts.TLSConfig = nil // disabled for faster local connection (even in production)if DBNumConns > 0 {opts.PoolSize = DBNumConns}db := NewTGPGDB(pg.Connect(opts))return db
}// Ping simulates a "blank query" behavior similar to lib/pq's
// to check if the db connection is alive.
func (db *TGPGDB) Ping() error {_, err := db.ExecOne("SELECT 1")return err
}// Migrate check and migrate to lastest db version.
func (db *TGPGDB) Migrate() error {// Make sure to only search specified migrations dircl := migrations.NewCollection()cl.DisableSQLAutodiscover(true)err := cl.DiscoverSQLMigrations(DBMigrationsDir)if err != nil {return err}var oldVersion, newVersion int64// Run all migrations in a transaction so we rollback if migrations fail anywhereerr = db.RunInTransaction(func(tx *pg.Tx) error {// Intentionally ignore harmless errors on initializing gopg_migrations_, _, err = cl.Run(db, "init")//if err != nil && !DBMigrationsAlreadyInit(err) {if err != nil{return err}oldVersion, newVersion, err = cl.Run(db, "up")return err})if err != nil {return err}if newVersion == oldVersion {fmt.Println("db schema up to date")} else {fmt.Println("db schema migrated successfully", zap.Int64("from", oldVersion), zap.Int64("to", newVersion))}return nil
}// WithContextTimeout
func WithContextTimeout(ctx context.Context, f func(ctx context.Context)) {WithContextTimeoutValue(ctx, DBStmtTimeout, f)
}// WithContextTimeoutValue
func WithContextTimeoutValue(ctx context.Context, timeout time.Duration, f func(ctx context.Context)) {// check context timeout setting with upper bound read/write limitif timeout > DBReadTimeout && timeout > DBWriteTimeout {fmt.Println(DBContextTimeoutExceedUpperBound,zap.Error(fmt.Errorf("query timeout %s exceed upper bound (%s|%s)", timeout, DBReadTimeout, DBWriteTimeout)))}newCtx, cancel := context.WithTimeout(ctx, timeout)f(newCtx)cancel()
}
直接运行 go run main.go,此时代码运行,会生成 students 数据表:
sql 如下:
执行后,会创建号数据表:students 和 gopg-migrations。
查看 gopg-migrations 如下:
2.2 假设我们要增加 sql 语句,怎么做呢?
直接添加 sql 重新运行 sql 如下:
执行如下:
查看 students 数据表,发现 1,2 操作都已经执行了:
2.3.管理 sql 语句
类似 1,2 中的方式,我们可以添加更多的 sql 语句,把 sql 管理起来。
总结
gopg-migrations 这个库,能够把数据库所有的操作 sql 全部管理起来,一方面可以让我们清晰的看到 sql 项目的发展历程,另一方面本地测试后发布更加安全!
以上所有内容均采用最新官方案例做示例
参考资料
查看全部代码 (https://github.com/turingczz/test_go_pg)
图片上传及查看,使用 swarm 网关实现(https://swarm-gateways.net/)
《酷Go推荐》招募:
各位Gopher同学,最近我们社区打算推出一个类似GoCN每日新闻的新栏目《酷Go推荐》,主要是每周推荐一个库或者好的项目,然后写一点这个库使用方法或者优点之类的,这样可以真正的帮助到大家能够学习到
新的库,并且知道怎么用。
大概规则和每日新闻类似,如果报名人多的话每个人一个月轮到一次,欢迎大家报名!戳「阅读原文」,即可报名
扫码也可以加入 GoCN 的大家族哟~