数据库多版本迁移

flyway是什么?

Flyway是一个简单开源数据库版本控制器(约定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客户端等,还提供一系列的插件支持(Maven、Gradle、SBT、ANT等)。

Flyway是独立于数据库的应用、管理并跟踪数据库变更的数据库版本管理工具。用通俗的话讲,Flyway可以像Git管理不同人的代码那样,管理不同人的sql脚本,从而做到数据库同步

注意:

flyway在执行脚本时,会在源数据表中检查checksum值,并确定上次运行到哪一个脚本文件,本次执行时从下一条脚本文件开始执行。所以编写脚本的时候不要去修改原有的脚本内容,并且新的脚本版本号要连续

为什么要使用flyway

通常在项目开始时会针对数据库进行全局设计,但在开发产品新特性过程中,难免会遇到需要更新数据库Schema的情况,比如:添加新表,添加新字段和约束等,这种情况在实际项目中也经常发生。那么,当开发人员完成了对数据库更的SQL脚本后,如何快速地在其他开发者机器上同步?并且如何在测试服务器上快速同步?以及如何保证集成测试能够顺利执行并通过呢?

在日常的开发中,我们使用git管理代码的版本,那么数据库的版本呢?使用flyway。

个人认为,可以大概的将flyway理解为数据库的git,方便多人协作及记录。

git:让你和同事更加轻松的维护同一个项目,你可以很方便的获取到他最新提交的改动。

flyway:让你及时的知道同事对数据库的改动并且能够自动在你的本地执行这些改动。

解决的问题

  1. 和同事同时维护一个项目,同时对数据库做出了一些修改,我在使用git拉取了最新的代码之后,运行总是报错,需要自己去重新执行一遍该表的创建语句来在本地进行创建,使用flyway后,拉取最新代码的同时会拉取最新的sql文件,同时在服务启动时自动创建数据表,对一些和自己无关的数据表完全不用关心了。

  2. 新接手一个项目,在本地进行开发调试,本地新建数据库后,需要执行一遍建表语句,使用flyway可以自动的创建该项目的所有表格。

其他相似工具

  1. 数据库迁移工具
github.com/golang-migrate/migrate
  1. git类型的数据库dolt
github.com/liquidata-inc/dolt   // 线上关系型数据库

(不适合) goway

使用方法:

https://blog.csdn.net/poem_2010/article/details/86241999

https://blog.csdn.net/weixin_39827798/article/details/111865637

安装对应的go库

go get github.com/poemp/goway  // 使用的人很少

配置

需要参数配置

type WayConfigure struct {
    Host       string
    Port       string
    User       string
    Password   string
    DbName     string
    SearchPath string // 数据库
    Table      string // 版本记录表名
    Path       string // 存放地址
}

首先需要做配置, 请在启动的时候重写

inter.DefaultTableDataSource = func() inter.WayConfigure {
        return inter.WayConfigure{
            Host:       host,
            Port:       port,
            User:       user,
            Password:   password,
            DbName:     dbName,
            SearchPath: searchPath,
            Table:      table,
            Path:       path,
        }
    }

然后, 调用手动执行

way.Flyway{}.Execu()
package main

import (
   "fmt"
   "github.com/jinzhu/gorm"
   "github.com/lunny/log"
   "github.com/poemp/goway/inter"
   "github.com/poemp/goway/way"
)

func main() {
   GetWayBD()
}

// GetWayBD 获取数据库连接
func GetWayBD() *gorm.DB {
   // 关闭
   defer func() {
      if e := recover(); e != nil {
         fmt.Println(fmt.Sprintf("recover from a fatal error : %v", e))
      }
   }()

   inter.DefaultTableDataSource = func() inter.WayConfigure {
      return inter.WayConfigure{
         Host:       "127.0.0.1",
         Port:       "9999",
         User:       "root",
         Password:   "123456",
         DbName:     "WorkStream",
         SearchPath: "searchPath",
         Table:      "table",
         Path:       "path",
      }
   }
   way.Flyway{}.Execu()
   c := inter.DefaultTableDataSource()
   source := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=%s password=%s",
      c.Host, c.Port, c.User, c.DbName, "disable", c.Password)
   log.Info("way datasource :" + source)
   // 支持其他的数据库, 需要修改这儿, 并且需要在代码中添加 其他数据库的驱动
   // 就像我使用的 post 数据库 是需要在import中加入:
   // _ "github.com/jinzhu/gorm/dialects/postgres"
   db, err := gorm.Open("postgres", source)
   db.SingularTable(true)
   db.LogMode(true)
   if err != nil {
      panic(err)
   }
   return db
}

踩坑点

需要修改 github.com/poemp/goway 里的db_config.go 依赖
github.com/go-xorm/core --->  xorm.io/core
image.png

(适合) golang-migrate

基本使用案例

Go migrate文档: https://pkg.go.dev/github.com/golang-migrate/migrate#New

简单的使用案例

cmd使用

https://github.com/golang-migrate/migrate/tree/master/cmd/migrate

Windows下载地址

https://github.com/golang-migrate/migrate/releases/download/v4.15.1/migrate.windows-amd64.zip

注: 下载完毕之后将里面的migrate.exe文件复制到咱们想要执行的目录下即可

Linux下载地址

https://github.com/golang-migrate/migrate/releases/download/v4.15.1/migrate.linux-arm64.tar.gz

golang-migrate使用

package main

import (
    "database/sql"
    "fmt"
    "github.com/golang-migrate/migrate/v4"
    "github.com/golang-migrate/migrate/v4/database/mysql"
    _ "github.com/golang-migrate/migrate/v4/source/file"
    "log"
)

func main() {
    // 连接数据库
    db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/workstream")
    
    if err := db.Ping(); err != nil {
        log.Fatalf("could not ping DB... %v", err)
    }

    // 开始迁移
    driver, _ := mysql.WithInstance(db, &mysql.Config{})
    m, err := migrate.NewWithDatabaseInstance(
        fmt.Sprintf("file://%s", "./migrations"), // file://path/to/directory
        "mysql", driver)
    if err != nil {
        log.Fatalf("migration failed... %v", err)
    }
    // 执行操作: up --> 更新,  down --> 回滚
    if err = m.Up(); err != nil && err != migrate.ErrNoChange {
        fmt.Printf("An error occurred while syncing the database.. %v", err)
    }
}

参考文章:

(重点: 函数的使用方法)https://blog.csdn.net/Matthew__M/article/details/123427027

(重点: migrate在gin中的应用)https://blog.csdn.net/weixin_26737625/article/details/108494299

(重点: migrate cli 实践)https://a2htray.github.io/2021/02/06/golang-migrate-usage-with-postgresql/

(重点: go migrate 测试)https://blog.csdn.net/doyzfly/article/details/121096806

(重点: go migrate 简单应用)https://www.cnblogs.com/super-egg/p/15080547.html

(重点) 项目中的使用

命令行用法

// 命令案例:  查看当前数据库版本
migrate -database mysql://root:123456@tcp(127.0.0.1:3306)/workstream -path . version

// 在当前migration文件夹里插入一个两个表(up, down)
migrate -database mysql://root:123456@tcp(127.0.0.1:3306)/workstream -path . create -ext sql -dir . -seq alter_users_column

------------------------------------------------------------------------------------------------------

Usage: migrate OPTIONS COMMAND [arg...]
       migrate [ -version | -help ]

Options:
  -source            迁移的位置 (driver://url)
  -path              sql脚本位置 -source=file://path
  -database          对此数据库运行迁移 (driver://url)
  -prefetch N        在执行之前要提前加载的迁移数 (default 10)
  -lock-timeout N    允许 N 秒获取数据库锁定 (default 15)
  -verbose           打印详细日志记录
  -version           打印 migrate 版本
  -help              打印用法

Commands:
  create [-ext E] [-dir D] [-seq] [-digits N] [-format] [-tz] NAME
         Create a set of timestamped up/down migrations titled NAME, in directory D with extension E.
         Use -seq    生成 N 位数字的顺序上/下迁移。 
         Use -format 指定 Go 时间格式字符串。注意:具有相同时间的迁移会导致"重复迁移版本"错误。
         Use -tz     指定生成非顺序迁移时将使用的时区(默认值:UTC)

  goto V             迁移到第 V 个数据库版本
  up [N]             应用所有或 N 个向上迁移
  down [N] [-all]    应用所有或 N 个向下迁移
  drop [-f]          (强制) 删除所有数据库中的数据
  force V            设置版本 V 但不运行迁移(忽略脏状态)
  version            打印当前迁移版本

Goland DDL映射

使用步骤

最终目的: 一句话概括, 将我们本地的sql脚本和远程数据库连接上! ! !

步骤1.png

步骤2.png

步骤3.png

步骤4.png

缺点:

只能映射sql脚本创建表的语句, 其他修改列字段相关的操作不支持, 且同步的时候会多出现一些key, 容易操作失误, 且版本回退没有清晰地表示, 只有相应时间点的改动, 不太专业.

项目场景

当线上数据库存在数据, 且需要后续添加, 修改, 删除字段

线上数据库能否回退版本并且有清晰地版本号, 令开发者一目了然

支持多人团队协作开发, 且功能全面

后面更新项目场景的解决问题......

你可能感兴趣的:(数据库多版本迁移)