数据库多版本迁移

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, 容易操作失误, 且版本回退没有清晰地表示, 只有相应时间点的改动, 不太专业.

项目场景

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

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

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容