Flyway基础简介

article/2025/11/10 9:10:29

1. 概述

Flyway是独立于数据库的应用、管理并跟踪数据库变更的数据库版本管理工具。
自动升级(自动发现更新项):Flyway 会将任意版本的数据库升级到最新版本。Flyway 可以脱离JVM 环境通过命令行执行,可以通过Ant 脚本执行,通过Maven 脚本执行(这样就可以在集成环境自动执行),并且可以在应用中执行(比如在应用启动时执行)。
规约优于配置:Flyway 有一套默认的规约,所以不需要修改任何配置就可以正常使用。
既支持SQL 脚本,又支持Java 代码:可以使用SQL 脚本执行数据库更新,也可以使用Java 代码来进行一些高级数据升级操作。
高可靠性:在集群环境下进行数据库升级是安全可靠的。
支持清除已存在的库表结构:Flyway 可以清除已存在的库表结构,可以从零开始搭建您的库表结构,并管理您的数据库版本升级工作。
支持失败修复。新的2.0 版本提供了repair 功能,用于解决数据库更新操作失败问题。

2. flyway基础

2.1概述

  • flyway通过在数据库中维护一张版本记录表(默认名称为flyway_schema_history),对数据库脚本操作进行版本管理,使得数据库的升级更新可以自动化;
  • flyway执行的脚本支持两种形式:一是使用SQL编写的.sql脚本,二是把SQL操作写到java代码里,通过执行java代码来执行SQL;
  • 每个.sql或.class文件都是一个版本,文件名称需要遵循flyway约定的格式;这个名称中包含了一个数字的版本信息,flyway通过这个版本来进行管理;

2.2 flyway组成

  • flyway包由三部分组成
    • commandline: 对输入的命令进行处理,确定配置文件路径,查找依赖包等;
    • core: 实现flyway核心的操作(migrate/info/clean等)和版本管理
    • maven-plugin和gradle-plugin: 用于帮助打可运行的jar包;
  • flyway由java语言编写,可以直接使用core来进行开发,而不需要使用commandline
    • 比如:自己建个springboot启动工程(web或application),在里面实例化Flyway对象,然后执行对应的操作
    • 比如:自己写个main方法,在里面实例化Flyway对象,然后执行对应的操作

2.3 flyway操作

命令说明
migrate执行最新版本的SQL脚本和java代码,把结果反映到数据库上
clean清除数据库中的所有表与数据,只剩下一个空的数据库
info列出用于维护版本信息的表内容,表名默认为flyway_schema_history
validate用实际的版本与数据库中已有的版本进行对比,检测意外修改(文件有checksum)
baseline设定基线版本,对于已存在数据的数据,必须设置基线版本,后面从该版本之后的版本进行操作
repair把版本表中失败的记录状态变成pending,然后可以重新操作
undo回滚对应版本,只有商用版本才支持

2.4 版本

  • Java文件
    在这里插入图片描述
  • SQL文件
    在这里插入图片描述
  • SQL文件与Java文件的不同之处仅在于后缀不同,一个是.sql(可配置),另外一个是.class(不可配置),其它是相同的;
  • 文件名(不含后缀)的格式
    • Prefix: 前缀,可以通过配置文件来设置
      • V: 代表正常版本管理;
      • U: 表示回滚,该操作比较危险,需要做详尽测试才能用,实践中最好不用;
      • R: 表示可以重复执行的版本,比如建视图、存储过程、函数等;
    • Version: 版本号,必须由数字(可加下划线或点)组成,重复执行的脚本不需要版本;
    • Separator: 分隔版本与description的分隔符,为两个下划线,可通过配置文件来修改,默认为两个下划线;
    • Description: 文件内容描述,建议用下划线分隔单词;
    • Suffix: 只针对于sql文件(java文件不适用),可通过配置文件来设置,默认为.sql;
  • Version
    • 一般情况下使用1~N的数字即可;
    • 考虑到实际开发中可能有多个分支进行操作,为了使得分支合并不冲突,可使用时间戳来做版本(中间可用下划线或点来分隔),时间戳越精确、冲突可能性越小;

2.5 路径

  • INSTALLDIR: 安装路径,即flyway解压所在的路径,其用于:
    • 加载${INSTALLDIR}/drivers下的各种数据库driver对应的jar包;
    • 加载${INSTALLDIR}/conf下的全局配置文件;
  • workingDirectory: 工作目录,可通过指定命令参数“-workingDirectory=xxxx”(不含双引号,xxx换成具体的绝对路径),如果不指定则等同INSTALLDIR;
    • 加载${workingDirectory}/jars里的jar包,通过java编写的代码需要打成jar放到该目录下才能通过命令行的方式访问到;
    • 加载${workingDirectory}/sql里的SQL脚本文件,这个目录会被配置文件flyway.conf里的flyway.locations的值替换掉(注意是替换掉,不是并集,这个地方不好理解,原理是这两个目录都是赋值给location变量,配置文件里有设置时会覆盖掉);
    • 在flyway.conf里的flyway.locations值,如果以filesystem:开头、且是相对路径的,都会基于此路径;
  • 注意:该部分在flyway官网文档中无说明(需要查看源码才能知晓),也不好理解,容易出错,需要好好理解(有比较多的地方并不遵循后面覆盖前面的逻辑,所以不好理解)。这些路径是在commandline中实现的,也就是说只有使用commandline才用到

2.6 配置

2.6.1 配置加载

配置主要来源于flyway.conf配置文件,按以下顺序和路径进行加载配置:

  1. 先加载${INSTALLDIR}/conf/flyway.conf(flyway.conf文件名不可更改);
  2. 加载System.property中配置user.home对应的路径下的flyway.conf文件(flyway.conf文件名不可更改),加载的配置若有相同则会覆盖之前加载的;
    • System properties可以通过下面方式增加
      • java启动时使用-D加的参数,如java -Dxxx=xxxx;
      • 在java代码中使用System.setProperty(“xxx”, “xxxx”)添加的参数;
  3. 加载当前目录下的flyway.conf文件(flyway.conf文件名不可更改),加载的配置若有相同则会覆盖之前加载的;
    • 在命令行中,terminal或cmd进入的路径为当前路径
    • 在java工程中运行则是工程根目录
    • 该操作有点隐蔽,注意理解;
  4. 若在环境变量中配置了flyway.configFiles,会加载这些文件,加载的配置若有相同则会覆盖之前加载的;
    • 该配置值可以有多个文件,用逗号分隔,每个文件可以有相对路径(不能使用绝对路径),文件名也不一定是flyway.conf;
    • 这些配置文件会基于 w o r k i n g D i r e c t o r y 来 构 成 完 成 路 径 , 也 就 是 这 些 文 件 需 要 放 到 {workingDirectory}来构成完成路径,也就是这些文件需要放到 workingDirectory{workingDirectory}目录下;
  5. 若命令行参数中带-configFiles参数指定了配置文件,则会加载这些文件,加载的配置若有相同则会覆盖之前加载的;
    • 若环境变量中配置了flyway.configFiles,则此配置参数无效;
    • 该配置值可以有多个文件,用逗号分隔,每个文件可以有相对路径(不能使用绝对路径),文件名也不一定是flyway.conf;
    • 这些配置文件会基于 w o r k i n g D i r e c t o r y 来 构 成 完 成 路 径 , 也 就 是 这 些 文 件 需 要 放 到 {workingDirectory}来构成完成路径,也就是这些文件需要放到 workingDirectory{workingDirectory}目录下;
  6. System.in输入的配置(貌似用于测试,待研究);
  7. 用逗号分隔flyway.locations的值,如果里面的路径不是绝对路径,则用${workingDirectory}补齐;
  8. 命令行还可以指定-flyway.xxxx=xxx形式的配置,这些配置会覆盖上面已载的配置项
    • 注意:此处配置项,不是加载配置文件;

注意:

  • 该部分在flyway官网文档中无说明(需要查看源码才能知晓),也不好理解,因为配置文件名大多是固定不可变的,而可以改变的手段有点特殊。
  • 要改变flyway.conf配置文件名称,只有两种方式;
  • 该部分主要属于commandline范畴,直接使用core则可以自行构造配置项或自行指定配置文件并加载;
  • 配置里的路径可以使用变量(原理待研究);
  • 在命令行中指定-workingDirectory=xxxx时,若也指定-configFiles=flyway.conf,则会比较明显地知道配置文件是在workingDirectory目录下,但如果不指定configFiles则需要flyway.conf放到命令行进入的目录中,会有点隐蔽;
  • 配置文件里参数读取后, 格 式 的 变 量 都 会 被 替 换 , 变 量 只 能 来 源 于 环 境 变 量 , 不 在 环 境 变 量 里 的 变 量 会 与 {}格式的变量都会被替换,变量只能来源于环境变量,不在环境变量里的变量会与 {}整体被替换为空(来源于命令行的参数没有此处理过程,故不能使用${}格式的变量);

2.6.2 常用配置

# 配置sql和java code查找路径:
#    sql文件路径必须以filesystem:(含冒号)开头,可以使用变量${workdir};
#    java code路径需要以classpath:(含冒号)开头,java代码需要打成jar包,并放到工作目录里的jars目录下,jar里的目录与该配置中classpath:后配置的路径一致;
# 开发环境不要修改此值,它会自动找工程目录下的db/sql中的sql脚本,以及代码目录com/everhomes/dbmigrate中的java代码(两种都会递归找子目录)
flyway.locations=filesystem:${workdir}/sql,classpath:com/everhomes/dbmigrate# 配置数据库连接,注意在url中不要配置用户名和密码
flyway.url=jdbc:mysql://127.0.0.1:13306/blogs?characterEncoding=UTF-8&serverTimezone=UTC
flyway.user=root
flyway.password=123456# 当需要低版本的脚本时,需要置成true,否则只能执行高版本的脚本
flyway.outOfOrder=true# 当数据库不是空数据库时,需要配置为true,空数据库则可以不配置
# flyway.baselineOnMigrate=true
# 配置了该版本后,migrate会从比该版本大的版本进行migrate,不配置时默认值为1
# flyway.baselineVersion=1# 有数据的数据库请保留此值为true,禁用clean命令,执行clean命令会清空数据库
flyway.cleanDisabled=true# 记录migrate历史记录的表名,默认为 flyway_schema_history
flyway.table=schema_version_history# migrate前后需要做某些操作时可使用此配置项,值为类名(带包路径),多个类名之间使用逗号分隔
# 每个类需要实现org.flywaydb.core.api.callback.Callback接口
# flyway.callbacks=com.everhomes.dbmigrate.core.MigrateCallBack

2.7 版本管理

支持SQL-base和Java-base两种管理方式,两种方式产生的版本文件是共同管理的,即在命令行或Java代码工程里都有可以同时执行.sql和.class提供的版本管理,执行顺序按版本号顺序;

2.7.1 SQL-base migrate

基于SQL的版本管理:

  • 文件名称需要符合版本格式
  • 文件可以被找到
    • SQL文件是通过flyway.locations配置项中指定以filesystem:开头的路径,可以有多个、用逗号分隔;
    • flyway.locations可以通过配置文件或命令行参数指定(参考上面“配置加载”章节说明);
    • 注意:flyway.locations值虽然可以通过多个途径配置,但只能配置一个值(值中可逗号分隔),注意加载的顺序和覆盖情况;
  • 确定上面两点后,即可执行flyway migrate/info/clean/repair 来进行版本管理;
    • 命令参数中可以按规范指定参数来帮助找到flyway.locations

2.7.2 Java-base migrate

基于Java的版本管理:

  • jar形式
    • 把开发的java代码打包jar包,放到${workingDirectory}/jars中
      • java代码须继承org.flywaydb.core.api.migration.BaseJavaMigration(推荐)或实现org.flywaydb.core.api.migration.JavaMigration接口,使用此方式仅依赖flyway和jdk提供的jar即可,配置环境简单;
      • java代码尽量使用flyway和jdk提供的类和自定义的类来进行操作,否则要解决包依赖问题;
    • java代码路径可被找到(在jar包里的路径)
      • java代码如果是放到db/migration路径下(可有子目录),则不用配置其它路径即可访问,因为flyway里默认给location加了个目录: classpath:db/migration
      • 如果不是放到db/migration路径下,则需要在flyway.locations里配置以classpath:开头的路径,该路径要与jar包里的路径一致;
  • java工程形式(在IDE里运行java工程的形式)
    • 工程启动运行有两种方式
      • 引flyway的commandline包
        • 可指定flyway的安装目录,或者自行依赖数据库driver包和flyway的core包;
        • 指定workingDirectory目录;
        • 指定flyway.conf的目录,或按规则放到commandline可找到的目录;
        • 运行后执行commandline提供的org.flywaydb.commandline.Main.main(args)
        • 优点:可利用commandline已经实现的命令操作,按命令的方式操作;
        • 缺点:需要遵循commandline的方式;
      • 实例化flyway并运行
        • 按springboot的方式启动或自行写main方法启动
        • 把flyway的core引入到工程中
        • 实例化flyway,并指定数据库连接,然后调用migrate()/clean()等方法
        • 优点:灵活;
        • 缺点:需要对flyway各命令所依赖的配置项有比较多了解,才好操作;
    • 该方式不受限于db/migration目录,可随意定目录,但为了部署时可以打包jar包,推荐遵循jar包所要求的目录方式;
  • 注意:
    • 该部署在官方文档说明不详细,比较模糊,特别是jar的方式就没有说明,部署时也只能使用jar方式;
    • 官方文档主要说明了“实例化flyway”方式,但其背后依赖的配置项和规则也没有说明;

2.7.3 callback

  • 版本管理操作有生命周期管理:整个操作开始前->单个版本操作开始前->单个statement操作开始前-> 具体操作 -> 单个statement操作后(报错后)-> 单个版本操作后(错误后)-> 整个操作后(错误后)
    • 整个操作可能包含多个版本,每个版本里可能有多个sql statement
    • 操作是指migrate、clean、repair等,参考上面操作说明
  • 这些生命周期节点可以设置callback来进行一些额外的处理
    • 在java代码中,需要实现org.flywaydb.core.api.callback.Callback接口,类路径无规定
      • 接口要实现supports()方法,在里面指定哪些操作归该Callback进行处理
      • 实现handle()方法,具体处理业务
      • canHandleInTransaction()在有事务时才涉及;
    • 在flyway.callbacks配置中指定callback的类路径(带包名,多个类之间使用逗号分隔),flyway.callbacks可以在flyway.conf中指定或者在命令行参数中指定(参考上面配置加载章节说明);
    • callback的类包需要包含在jar中,才能在命令行里操作;

2.7.4 不支持MySQL5.6

  • 在org.flywaydb.core.internal.database.mysql.MySQLDatabase.ensureSupported()中有对MySQL数据库的版本进行判断,小于5.7的版本不支持(MARIADB是MySQL的一个分支,都在MySQLDatabase中实现)。
  • 除此之外,没有其它地方控制这个版本。抛出的错误说enterprise版本支持,但除非换代码,否则感觉也不支持。
  • 要支持5.6,可以修改此类编译与.class,然后替换掉core包里的该类。
public final void ensureSupported() {ensureDatabaseIsRecentEnough("5.1");if (databaseType == DatabaseType.MARIADB) {ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("10.1", org.flywaydb.core.internal.license.Edition.ENTERPRISE);ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("10.2", org.flywaydb.core.internal.license.Edition.PRO);recommendFlywayUpgradeIfNecessary("10.4");} else {ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("5.7", org.flywaydb.core.internal.license.Edition.ENTERPRISE);if (JdbcUtils.getDriverName(jdbcMetaData).contains("MariaDB")) {LOG.warn("You are connected to a MySQL " + getVersion() + " database using the MariaDB driver." +" This is known to cause issues." +" An upgrade to Oracle's MySQL JDBC driver is highly recommended.");}recommendFlywayUpgradeIfNecessary("8.0");}
}protected final void ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition(String oldestSupportedVersionInThisEdition, Edition editionWhereStillSupported) {if (!getVersion().isAtLeast(oldestSupportedVersionInThisEdition)) {throw new FlywayEditionUpgradeRequiredException(editionWhereStillSupported,databaseType,computeVersionDisplayName(getVersion()));}
}

2.7.5 版本比较

  • flyway把版本都封装在org.flywaydb.core.api.MigrationVersion类里
  • 比较的原理
    • 先把版本中的下划线(_)替换成点(.),不支持其它非数字字符,有的话会报错;
    • 把版本以点进行分隔成多个数字(点分隔的每段一个数字);
    • 把每一段数字转成Bigdecimal,即版本的每段数字都可以很大,即使精确到毫秒的时间戳作为版本也支持;
    • 两个版本之间进行比较
      • 取两个版本中段数量大的段数作为循环次数;
      • 循环比较,从左到右,每一段相比(Bidecimal相比),某段大的则版本大,若段数不够则用0代替;
  • 注意
    • 每段都是数字值相比,不是按字符串相比
    • 段数的多或少并不能说明版本的大小,比如并不是段数多的版本大;
    • 段是从左到右比的,哪段先大就版本大;

2.8 日志

  • flyway本身提供了日志的方式,但实现也比较混乱
    • 比如可以通过命令行参数指定-outputFile=xxx或-logFile=xxx来输出日志文件,通过指定-X或-q来分别控制日志的级别为DEBUG或WARN,但这些参数生效的前提是在环境中找不到slf4j等常用的日志方式才会生效
    • 这些日志的格式无法控制,打印出来的日志时间没有日期
  • 使用logback
    • 依赖slf4j相关的三个包:logback-classic-1.2.3.jar、logback-core-1.2.3.jar、slf4j-api-1.7.25.jar
      • java代码工程环境直接依赖即可
      • 命令行环境则需要把这些包放到${INSTALLDIR}/lib,可能也可以用其它方式依赖(待研究);
    • logback.xml文件路径
      • 在java代码工程环境中,如果是使用springboot环境,则直接放到classpath中即可找到(springboot有自己找logback的方式),否则依赖slf4j的查找方式(待研究);
      • 在命令行环境中,可在java命令启动的时候加入-Dlogback.configurationFile=xxx/logback.xml 参数来指定logback.xml文件(不确定是否有更优雅的方式,待研究)

http://chatgpt.dhexx.cn/article/B3b4xIEk.shtml

相关文章

flyway的学习总结

一、简单介绍 Flyway 是一款开源的数据库版本管理工具。它可以很方便的在命令行中使用,或者在Java应用程序中引入,用于管理我们的数据库版本。 在项目或产品中,很难一开始就把业务理清楚,把数据库表设计好,因此数据表…

Flyway——配置和使用(入门)

文章目录 介绍测试环境依赖引入配置数据库连接启动类设置脚本项目结构概览项目启动,观察日志和数据库结果测试R开头的脚本直接重启项目修改 R__add_user_info.sql 后重启 变更数据库字段验证 V 只能执行一次的问题验证 R 可执行多次验证只有一个_会报错技能扩充参考…

flyway的快速入门教程

目录 一、简单介绍 二、为什么要使用flyway 三、flyway是如何工作的 四、如何使用flyway 1、先要初始化一个SpringBoot项目,引入依赖 2、在application.yml中添加相关配置 3、根据配置文件中填写的脚本存放路径,创建文件夹 4、添加需要运行的sql…

Flyway详解(使用说明及避坑指南、一文搞懂flyway)

一、简介 1.1 Flyway是什么? Flyway是一款开源的数据库版本管理工具,可以实现管理并跟踪数据库变更,支持数据库版本自动升级,而且不需要复杂的配置,能够帮助团队更加方便、合理的管理数据库变更。 例:创建…

MySQL数据库的集群解决方案(一)

读写分库架构 我们一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案: 其中一个是主库,负责写入数据,我们称之为:写库; 其它都是…

MySQL数据库集群实战(1)——MySQL数据库基础知识

文章目录 一、为什么使用数据库?二、数据库概念数据库(DataBase,DB)数据库管理系统(DataBase Management System,DBMS)SQL概述 三、数据库存储文件的特点四、MySQL常见的数据对象五、MySQL数据类…

mysql-集群概述

mysql-主从模式 mysql-集群概述 可用性设计 站点高可用,冗余站点服务高可用,冗余服务 数据高可用,冗余数据 保证高可用的方法是冗余。但是数据冗余带来的问题是数据一致性问题 实现高可用的方案有以下几种架构模式: 主从模式 简…

MySQL数据库集群的原理与搭建

【1.应用背景】 在最近做的项目中,因为有一个短时间内很多人访问服务,会频繁访问数据库,看到这里不免有些人会想起数据库集群。我们组长也想到了用数据库集群,于是就带着我们几个研究起来了mysql数据库集群的搭建。因为我们几个的…

MySQL 数据库主从集群搭建

文章目录 1 准备工作2 配置主数据库3 配置从库4 从库设置只读用户5 推荐参考资料 1 准备工作 1 选择一个服务器当做主服务器,将服务器上需要的数据进行备份 2 安装从库的 MySQL,需要与主服务器的版本保持一致 3 将主服务器上的数据同步到从库中(主从集…

MySQL数据库主从集群架构搭建

一、相关概念 二、配置一主一从 三、配置一主多从 四、配置主从从 五、配置主主结构 六、配置半同步复制模式 一、相关概念 1.1 主从同步介绍: 存储数据的服务结构,分为2种角色: 主服务器(master):接受客户端访问连接 从服务器(sl…

谈谈mysql数据库集群

现在,随着上网人数的激增,一些大型的网站开始使用数据库集群来提高数据库的可靠性和数据库的性能。那么在介绍数据库集群之前首先需要弄清楚几个问题。 1.为什么要用数据库集群 (1)通过使用数据库集群可以使读写分离,提…

MySQL集群配置

1. MySQL集群简介 MySQL Cluster 是MySQL适合于分布式计算环境的高实用、高冗余版本。它采用了NDB Cluster 存储引擎,允许在1个 Cluster 中运行多个MySQL服务器。MySQL Cluster 是一种技术,该技术允许在无共享的系统中部署“内存中”数据库的 Cluster 。…

MySQL数据库集群(双主双从)

文章目录 MySQL数据库集群(双主双从)实验环境双主双从双主双从进行测试 MySQL数据库集群(双主双从) 实验环境 保证每台centos7服务器配置静态的IP,初始化服务器,关闭防火前和selinux,保证四台服务器之间可以互相通信,并且做好hosts域名解析…

数据库与集群

数据库与集群 1、数据库集群 概念:数据库集群,顾名思义,就是利用至少两台或者多台数据库服务器,构成一个虚拟单一数据库逻辑映像,像单数据库系统那样,向客户端提供透明的数据服务。 数据库集群两个关键定…

数据库-mysql集群方案总结

一 概念解读 1 数据库高可用 高可用指的是:如果数据库发生了宕机或者意外中断等故障,能尽快恢复数据库的 可用性,保证业务不会因为数据库的故障而中断。 另外,数据库高可用还要数据一致性,如下: (1) 用作备份、只读副…

数据库集群

目录 主从复制集群单机数据库的问题单机到集群主从复制传统主从复制异步复制半同步复制 组复制(MGR MySQL Group Replication MGR ) 主从复制演示准备两个MySQL服务实例修改主数据库MySQL_A的my.ini中的[mysqld]配置项下的配置如下修改从数据库MySQL_B的…

MySQL数据库的集群方案

1.简介 我们一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案: 其中一个是主库,负责写入数据,我们称之为:写库; 其它都是从库&…

MySQL集群解决方案(1):MySQL数据库的集群方案

1、系统架构存在的问题 在我们的系统架构中,DBserver方面我们只是使用了单节点服务,如果面对大并发,海量数据的存储,显然单节点的系统架构将存在很严重的问题,所以接下来,我们将实现MySQL的集群&#xff0c…

C语言回调函数详解及实例

C语言回调函数详解及实例 回调函数:函数 F1 调用函数 F2 的时候,函数 F1 通过参数给函数 F2 传递了另外一个函数 F3 的指针,在函数 F2 执行的过程中,函数F2 调用了函数 F3,这个动作就叫做回调(Callback&…

回调函数

什么是回调函数? 有以下三点 1、自己创建的函数; 2、没有调用; 3、但是函数执行了(在某个条件下)。 例如: 1.定时器函数 var a 1setItercal( function(){aconsole.log(a)},1000)//延时器var a 1setTimeout( functi…