国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

时间:2022-12-26 12:08:38

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

作者:楚乔  

路特斯(Lotus)运维开发工程师

在国际化多机房部署的场景下,国内生产部署的是最新版本,国外部署的是落后 1 个甚至 N 个迭代的版本。当业务需要在国外升级到指定中间版本时,当前只能靠运维根据现有版本和指定中间版本之间的 N 次发布文档,挨个汇总 SQL 变更内容,非常费时费力,且容易出错。

因为想要自动化整个数据变更流程,所以选用社区比较有名的 go-migrate 和比较主流的数据库变更工具 flyway 做相应的尝试,并最终对 go-migrate 做二次开发来实现上述能力

下面分享我们对这两个方案的验证过程及具体实践,以供社区同学参考。

方案描述

以数据库为单位,建立单独 GitLab 项目管理数据库所有的 SQL 变更,变更范围以版本为单位。

工具选型

工具

go-migrate [1]

flyway [2]

Github stars

9.6K

6.7K

功能

类似 python flask框架 migrate 功能

undo 等重要功能需要买企业版

版本对比 [3]

复杂度

适中

较高

源码

完全开源

有开源版和企业版

多个微服务共用一个数据库

不支持,可简单二开支持

不支持,二开复杂度较高

 

下面主要介绍

这两个工具的最小 demo 供大家参考。

flyway

前置准备

  • 安装 flyway

    从官网下载 flyway cli 工具 [4] 并安装,选择适合自己电脑操作系统和芯片架构的二进制文件。

     

  • 准备数据库

    使用 Datagrip 工具创建测试数据库用于 demo。

  •  
1 create database flyway_test default character set utf8mb4 collate utf8mb4_unicode_ci;

 

  • 准备项目

    创建 spring boot 测试项目 mysql-test ,pom.xml 文件中增加 flyway 依赖。

1<dependencies>2    <dependency>3        <groupId>org.springframework.boot</groupId>4        <artifactId>spring-boot-starter-data-jpa</artifactId>5    </dependency>6    <dependency>7        <groupId>org.flywaydb</groupId>8        <artifactId>flyway-core</artifactId>9       <version>6.0.8</version>10    </dependency>11    <dependency>12        <groupId>mysql</groupId>13        <artifactId>mysql-connector-java</artifactId>14        <scope>runtime</scope>15    </dependency>16</dependencies>17
18<build>19    <plugins>20        <!--flyway-->21        <plugin>22            <groupId>org.flywaydb</groupId>23            <artifactId>flyway-maven-plugin</artifactId>24           <version>6.0.8</version>           25            <!--配置属性-->26            <configuration>27                <user>root</user>28                <password>root</password>29                <url>jdbc:mysql://127.0.0.1:3306/flyway_test</url>30            </configuration>31        </plugin>32    </plugins>33</build>

application.yml 文件中增加数据源配置 

1spring:2 datasource:3    driverClassName: com.mysql.cj.jdbc.Driver4    url: jdbc:mysql://localhost:3306/flyway_test?serverTimezone=UTC&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false5    username: root6    password: root7  # flyway8  flyway:9    baseline-on-migrate: true10    locations: classpath:/db/migration11    check-location: true12    enabled: true13  #jpa14  jpa:15    database: MYSQL16    show-sql: true17    hibernate:18      ddl-auto: none

增加 SQL 变更文件,注意目录为 src/main/resources/db/migration

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

sql 文件命名规则

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

  • 首位大写字母V ,固定格式;

  • 后面跟上版本号,版本号为数字、点、或者下划线组成;

  • 版本号后跟上__(注意:这里是两位下划线),固定格式;

  • __后跟上文件描述,无限制,最好做到见文知意,如:V2_creatTableStudent.sql

本地验证

本地执行以下命令

1 # 本机 mac 执行2 mvn clean package -U -Dmaven.test.skip=true -e3 ./lotus.sh4 
5 2022-08-30 10:15:25.347  INFO TID: N/A 98445 --- [           main][] o.f.core.internal.command.DbMigrate      : Current version of schema `flyway_test`: << Empty Schema >>6 2022-08-30 10:15:25.358  INFO TID: N/A 98445 --- [           main][] o.f.core.internal.command.DbMigrate      : Migrating schema `flyway_test` to version 1 - init7 2022-08-30 10:15:25.567  INFO TID: N/A 98445 --- [           main][] o.f.core.internal.command.DbMigrate      : Migrating schema `flyway_test` to version 2 - create route8 2022-08-30 10:15:25.703  INFO TID: N/A 98445 --- [           main][] o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema `flyway_test` (execution time 00:00.373s)9 2022-08-30 10:15:25.799  INFO TID: N/A 98445 --- [           main][] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]10 2022-08-30 10:15:25.851  INFO TID: N/A 98445 --- [           main][] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.6.7.Final11 2022-08-30 10:15:25.980  INFO TID: N/A 98445 --- [           main][] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}12 2022-08-30 10:15:26.173  INFO TID: N/A 98445 --- [           main][] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect13 2022-08-30 10:15:26.311  INFO TID: N/A 98445 --- [           main][] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]14 2022-08-30 10:15:26.319  INFO TID: N/A 98445 --- [           main][] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

执行后数据库 flyway_schema_history 表新增 SQL 变更记录

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

版本降级

1 mvn flyway:undo2 [ERROR] Failed to execute goal org.flywaydb:flyway-maven-plugin:6.0.8:undo (default-cli) on project redis-test: org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException: Flyway Pro Edition or Flyway Enterprise Edition upgrade required: undo is not supported by Flyway Community Edition.

* 很遗憾,flyway 社区版不支持 undo 功能。

在 Zadig 上实践 flyway

参考「Zadig + Flyway 工作流统一数据和代码变更,研发更丝滑」[5]

go-migrate

前置准备

安装 migrate

从官方下载 migrate 工具 [6]并安装 ,选择适合自己电脑操作系统和芯片架构的二进制文件。

 

准备数据库

使用 Datagrip 工具创建测试数据库用于 demo

1 create database redis_test default character set utf8mb4 collate utf8mb4_unicode_ci;

准备项目

准备 spring boot 测试项目 migration-test,编写 migrate sql

1 # 1_initialize_schema.up.sql2 # 如果是业务表,可以考虑create table if not exists3 create table alert4 ...5    charset = utf8mb4;6
7 create index IX_alert_select_18    ...
1 # 1_initialize_schema.down.sql2 # 如果是业务表,里面有业务数据,建议版本回退的时候不做drop操作3 drop table if exists alert;

将 SQL 变更记录(各版本增量更新的 up、down 语句)保存在项目指定目录下,发布时,执行 migrate up 命令。示例如下:

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

文件命名规则:

1 {version}_{title}.up.{extension}2 {version}_{title}.down.{extension}

参数说明:

  • {version} —— 64 位无符号整数,该值需要随着版本趋势增长并保持唯一,比如1,2,3,4...

  •  {title} —— 本次 SQL 变更的简单英文标识 

  • {extension} —— SQL 变更文件后缀,比如.sql 

 

本地验证

migrate 组件目前对支持 多个微服务共用一个数据库,且都需要改变表结构 的场景还不完善,可以考虑在原生功能的基础上进行二开,下述内容为二开后的实践。

 

1. 执行 migrate up 命令,自动执行所有 up.sql,更新到最新版本

1 shell➜  migrate-test git:(master) ✗ migrate -appname "migrate-test" -source "file://migrations" -database "mysql://root:root@tcp(localhost:3306)/migrate_test" up  2 1/u initialize_schema (180.104ms)3 2/u create_route (276.570667ms)4 3/u create_notify (380.573625ms)

2. 执行 migrate down 1 命令,回退版本3

1 shell➜  migrate-test git:(master) ✗ migrate -appname "migrate-test" -source "file://migrations" -database "mysql://root:root@tcp(localhost:3306)/migrate_test" down 12 3/d create_notify (39.362042ms)

3. 执行 migrate down 命令,回退到初始状态

1 shell➜  migrate-test git:(master) ✗ migrate -appname "migrate-test" -source "file://migrations" -database "mysql://root:root@tcp(localhost:3306)/migrate_test" down  2 Are you sure you want to apply all down migrations? [y/N]3 y4 Applying all down migrations5 2/d create_route (73.9035ms)6 1/d initialize_schema (116.148333ms)

 

4. 执行 migrate goto 2 命令,更新到指定中间版本2

1 shell➜  migrate-test git:(master) ✗ migrate -appname "migrate-test" -source "file://migrations" -database "mysql://root:root@tcp(localhost:3306)/migrate_test" goto 22 1/u initialize_schema (178.743125ms)3 2/u create_route (280.408375ms)

5. 执行 migrate down 1 命令,回退版本2

1 shell➜  migrate-test git:(master) ✗ migrate -appname "migrate-test" -source "file://migrations" -database "mysql://root:root@tcp(localhost:3306)/migrate_test" down 12 2/d create_route (52.728416ms)

 

6. 执行 migrate down 1 命令,回退版本1

1 shell➜  migrate-test git:(master) ✗ migrate -appname "migrate-test" -source "file://migrations" -database "mysql://root:root@tcp(localhost:3306)/migrate_test" down 12 1/d initialize_schema (56.16175ms)

 

在 Zadig 上实践 go-migrate

1. 将服务添加到 Zadig 中并创建构建,在构建脚本中添加 migrate 命令及相关参数,将代码中的 .sql 文件应用到数据库

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

2. 运行工作流,验证代码中的 SQL 和数据库存在差异时的效果(初次运行将变更应用到数据库,显示变更对应的文件及执行耗时)

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

再次运行工作流,验证代码中的 SQL 和数据库无差异时的效果(第二次运行,无 SQL 变更,显示 no change 

国际化多版本环境如何用 Zadig + Migrate 统一数据和代码变更

当数据库中的 SQL 版本低于代码中时, migrate up 命令会将数据库中的 SQL 更新到和代码一致;当数据库中的 SQL 与代码中一致时, migrate up 命令不会执行任何操作。

 

参考链接

[1] https://github.com/golang-migrate/migrate

[2] https://github.com/flyway/flyway

[3] https://flywaydb.org/download

[4] https://flywaydb.org/download/community

[5] https://mp.weixin.qq.com/s/KFyKkYTQp58BpNn9HGA7AQ

[6] https://github.com/golang-migrate/migrate/releases

 

Zadig,让工程师更专注创造!