Flyway

Database Migrations Made Easy.

Flyway

介绍

Flyway是一款数据库迁移(migration)工具,在你部署应用的时候,帮你执行数据库脚本的工具,Flyway支持SQL和Java两种类型的脚本,你可以将脚本打包到应用程序中,在应用程序启动时,由Flyway来管理这些脚本的执行,这些脚本被Flyway称之为Migration。

特点

  • 简单 非常容易安装和学习,同时迁移的方式也很容易被开发者接受。
  • 专一 Flyway 专注于搞数据库迁移、版本控制而并没有其它副作用。
  • 强大 专为连续交付而设计。让Flyway在应用程序启动时迁移数据库。

软件架构

SpringBoot + Flyway + 支持 (Mysql、Oracle、DM(达梦)、PG、sqlServer等关系型数据库)

使用说明

  1. 添加脚本db/migration文件下根据顺序新增。
  2. 如果设计文档或者特殊数据处理可以在db.migration包下使用JAVA代码执行。
  3. 版本号命名:如果在db/migration下的版本号那么在db.migration下递增版本号,反之在db.migration有了版本号在db/migration也是递增。
  4. 执行过的脚本不能再次执行需要另行加新版本修改执行即可。
  5. 参考范例自行扩展。

Flyway 中的常用概念

Flyway 中的概念可查阅 官方文档,这里挑选一些重要的进行简单介绍。

Schema History Table

Flyway 对数据库进行版本控制的方式,是在指定数据库中创建一张表,即 Schema History Table(默认为 flyway_schema_history),记录由 Flyway 所执行的 sql 脚本状态。

Migration(核心)

在 Flyway 中,所有对数据库的变动,均称为 migration,migration 可以是 SQL 文件,也可以是 Java 类。

默认的查找 migration 的路径为 classpath:db/migration,对应 SQL 文件可放置在 src/main/resources/db/migration 下,Java 类可放置在 src/main/java/db/migration 下。

Migration 可以是仅执行一次的(versioned),也可是重复执行的(repeatable)。

Versioned Migration

1、Versioned migration 包括版本号、描述和校验值(checksum,自动计算),命名方式如下:

Versioned Migration

其中版本号必须全局(一个 Schema History Table 里)唯一,且默认情况下(可通过参数调整)版本号只能增加,不能在已经执行了高版本的 migration 之后再执行低版本的 migration。

注意点:sql脚本与java类,共享版本号。

2、版本号可以是数字加 . 的形式,例如下列都是合法的版本号:

1
001
5.2
1.2.3.4.5.6.7.8.9
205.68
20130115113556
2013.1.15.11.35.56
2013.01.15.11.35.56

3、Flyway 是如何比较两个 SQL 文件的先后顺序呢?它采用 采用左对齐原则, 缺位用 0 代替 。举几个例子:

1.0.1.1 比 1.0.1 版本高。

1.0.10 比 1.0.9.4 版本高。

1.0.10 和 1.0.010 版本号一样高, 每个版本号部分的前导 0 会被忽略。

了解

checksum 用来检查 migration 在执行过后是否发生了变化,如果发生了变化,会导致这个版本以及后续版本的 migration 无法执行。

Repeatable Migration

Repeatable migration 包括描述和校验值,没有版本号信息,会在每次校验值(migration 内容变化会导致校验值变化)发生变化时重复执行,命名方式如下:

Repeatable Migration

Repeatable migration 会在所有的 versioned migration 都执行过后再进行执行,Repeatable migration 内部按照其文件名中描述(description)部分的顺序执行。

在 repeatable migration 中需保证其中内容可重复执行,比如在 DDL 中使用 CREATE OR REPLACE

Baseline

当数据中已经存在内容时,再引入 Flyway,可通过 Baseline 设定一条基线。

Baseline

如果想将基线之前的数据库中表结构和数据纳入 Flyway 一同管理,可以将基线前的状态导出成数据库脚本,通过 versioned migration 添加至 flyway 中,并设定 baselin version,Flyway 会忽略基线版本号(包括)之前版本的所有 migration。

如果不想管理基线之前的数据库状态(比如多模块或应用操作同一数据库,互相之间不受影响),可以只告诉 Flyway 执行 migration 的时候是存在基线的,这样就不会报出数据库非空的异常。

如何在一个 Spring Boot 项目中引入 Flyway

在 Spring Boot 项目中,引入 Flyway 非常简单,因为在 Spring Boot 的 spring-boot-autoconfigure 中包含了 Flyway 的自动配置,只要添加 flyway 的依赖即可。开箱即用

org.flywaydb flyway-core

添加 Flyway 依赖后,无需其他配置,Flyway 的功能是自动启用的,如果想停用 Flyway,需设置 spring.flyway.enabled=false

添加 sql 脚本

引入 Flyway 之后,再启动应用时,会在默认路径 classpath:db/migration 查找 sql 脚本,如果没找到会报错,影响应用启动。

可在 src/main/resources/db/migration 路径下创建 sql 文件,如 src/main/resources/db/migration/V20220530__test.sql,使应用可正常启动。

启动成功后,可在所指定的数据库中的 flyway_schema_history 表中查看初始化脚本执行状态。

可通过 spring.flyway.table=another_table 修改默认表名。

修改默认表名,可实现多个模块分别通过 Flyway 进行数据库版本控制,并连接到相同数据库的效果。

非空数据库处理

当在一个已有项目中引入 Flyway 时,数据库中可能已经存在了一些表和初始化数据,此时按照上述方式引入 Flyway 时会提示如下异常:

TEXT1org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Found non-empty schema(s) `demo` but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.

此时需要设定 spring.flyway.baseline-on-migrate=true 参数,告诉 Flyway 在执行 sql 脚本之前,数据库是非空状态。

如果想指定 baseline version,可通过设定 spring.flyway.baseline-version=20210809 参数,以忽略 20210809 版本以及之前的所有 migration。

其他问题

执行方式

Flyway 的 migration 会在 Spring Boot 应用启动时自动执行,如果不想通过启动应用的方式执行,官方提供了命令行、API、以及 Maven 和 Gradle 插件的方式,但总的来说都会麻烦一些,因为需要将已经在 Spring Boot 中配置的参数,再到其他执行方式所各自要求的位置重新配置一遍,实用性一般。

生产环境数据安全性

Flyway 的 Clean 命令,会将 Flyway 所连接的数据库中的所有内容全部清理掉,不论其中的表或数据是否是通过 Flyway 添加进去的。

在生产环境中使用 Flyway 确实也存在一定的风险,但这个风险不是 Flyway 本身造成的,有权连接生产库的人的任何一个误操作,都会导致生产环境数据的丢失,建议不要因噎废食。

Flyway 对此也提供了一定的防范措施,可通过禁用 Clean 命令来防止此问题发生,比如通过 Spring Boot 的 spring.flyway.clean-disabled=true 参数。

建议在所有环境都禁用 Clean 命令。

SQL 报错

通过 Spring Boot 自动执行 migration 时要注意,一旦 migration 执行失败,应用启动会终止。出现 migration 执行失败时,需要将 Schema History Table 表中的失败记录处理掉,才能再次执行 migration,否则应用会一直无法启动。

out-of-order

多人开发时,可能会出现 A 写了 V1 脚本,B 写了 V2 脚本,B 的代码先合并进去了,V2 脚本先执行了,此时 A 的 V1 脚本受版本号只能增加的要求不能再执行。

这种情况可以通过将 spring.flyway.out-of-order 设置为 true 来暂时取消这个限制(不推荐 ),

强烈建议 A 将 V1 脚本版本号改为 V3。

使用姿势

flyway⽂件只能追加,不能修改⽂件本⾝,如果之前flyway添加的数据有问题,需要新添加flyway⽂件然后再⽂件中执⾏脚本删除之前的有问题数据。
每次新建flyway⽂件需要再本地dev环境运⾏成功后才能push。

Flyway配置释义:

对执行迁移时基准版本的描述.
flyway.baseline-description

当迁移时发现目标schema非空,而且带有没有元数据的表时,是否自动执行基准迁移,默认false.
flyway.baseline-on-migrate

开始执行基准迁移时对现有的schema的版本打标签,默认值为1.
flyway.baseline-version

检查迁移脚本的位置是否存在,默认false.
flyway.check-location

当发现校验错误时是否自动调用clean,默认false.
flyway.clean-on-validation-error

是否开启flywary,默认true.
flyway.enabled

设置迁移时的编码,默认UTF-8.
flyway.encoding

当读取元数据表时是否忽略错误的迁移,默认false.
flyway.ignore-failed-future-migration

当初始化好连接时要执行的SQL.
flyway.init-sqls

迁移脚本的位置,默认db/migration.
flyway.locations

是否允许无序的迁移,默认false.
flyway.out-of-order

目标数据库的密码.
flyway.password

设置每个placeholder的前缀,默认${.
flyway.placeholder-prefix

是否要被替换,默认true.
flyway.placeholder-replacementplaceholders

设置每个placeholder的后缀,默认}.
flyway.placeholder-suffix

设置placeholder的value
flyway.placeholders.[placeholder name]

设定需要flywary迁移的schema,大小写敏感,默认为连接默认的schema.
flyway.schemas

迁移文件的前缀,默认为V.
flyway.sql-migration-prefix

迁移脚本的文件名分隔符,默认__
flyway.sql-migration-separator

迁移脚本的后缀,默认为.sql
flyway.sql-migration-suffix

使用的元数据表名,默认为schema_version
flyway.tableflyway

迁移时使用的目标版本,默认为latest version
flyway.target

迁移时使用的JDBC URL,如果没有指定的话,将使用配置的主数据源
flyway.url

迁移数据库的用户名
flyway.user

迁移时是否校验,默认为true.
flyway.validate-on-migrate
spring:
# 一般配置
  flyway:
  	# 禁用clean,默认false (重要!)
    clean-disabled: true
    # 是否启用flyway,默认true (重要)
    enabled: true
    # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表,默认true (重要)
    baseline-on-migrate: true
    # 是否允许无序迁移,默认false
   	out-of-order: false
    # 编码格式,默认UTF-8
    encoding: UTF-8
    # 迁移sql脚本文件存放路径,默认db/migration
    locations: classpath:db/migration
    # 迁移sql脚本文件名称的前缀,默认V
    sql-migration-prefix: V
    # 迁移sql脚本文件名称的分隔符,默认2个下划线__
    sql-migration-separator: __
    # 迁移sql脚本文件名称的后缀
    sql-migration-suffixes: .sql
    # 迁移时是否进行校验,默认true
    validate-on-migrate: true
   	
posted on 2022-08-19 10:53  狸语  阅读(975)  评论(0编辑  收藏  举报