本文介绍: Flyway详解,包含工作原理使用说明、避坑指南、以及团队使用时的注意事项

一、简介

1.1 Flyway是什么?

Flyway是一款开源数据库版本管理工具可以实现管理并跟踪数据库变更,支持数据库版本自动升级,而且不需要复杂的配置,能够帮助团队更加方便、合理管理数据库变更。
例:创建两个sql变更文件项目启动后会将两个文件中的sql语句全部执行

1.2 为什么使用Flyway?

简单举个例子:开发时,如果A开发和B开发都对同一数据库进行了修改,那么如何进行数同步呢?假如多个开发人员修改sql脚本,怎么同步测试环境和生产环境
类似于以上的情况在日常开发中不胜枚举,在最开始的单体架构中,我们公司采用了通过校验数据库版本号实现sql的变更,这虽然能够解决大部分问题,但每次都需要维护变更sql代码数据库版本号,且对于后续服务上云也是十分不便的。因此我们需要数据库校验的方案进行调整,就去调研了目前市面上比较流行的Flyway和Liquibase综合对比下来,最终选择了Flyway作为后续的数据库版本管理工具,具体差异如下:
在这里插入图片描述

1.3 Flyway的工作原理

Flyway在第一次执行时,会创建一个默认名为flyway_schema_history的历史记录表,这张表会用来跟踪或记录数据库状态然后每次项目启动时都会自动扫描在resources/db/migration下的文件版本号并且通过查询flyway_schema_history来判断是否有新增文件,从而判断是否进行迁移
默认查找 migration 的路径classpath:db/migration ,对应 SQL 文件可放置在src/main/resources/db/migration 下,Java 类可放置在 src/main/java/db/migration 下。
Flyway在第一次执行时,会创建一个默认名为flyway_schema_history的历史记录表,这张表会用来跟
踪或记录数据库状态然后每次启动时都会自动扫描在resources/db/migration下的文件并且通过查
询flyway_schema_history来判断是否为新增文件,从而判断是否进行迁移
默认查找 migration 的路径为 classpath:db/migration ,对应 SQL 文件可放置在
src/main/resources/db/migration 下,Java 类可放置在 src/main/java/db/migration 下

1.3.1 Flyway的校验版本号算法

flyway在升级数据库时会先计算之前已经升级过的脚本checksum值和数据库的checkSum值进行比对,如果老脚本发生了变化后checkSum校验就会失败,从而抛出异常,checkSum计算算法为(CRC32 (循环冗余校验码)算法)。
新增的脚本则会和数据库中的版本号进行比较,如果小于数据库存储最后一个版本号,也不会继续执行

1.3.2 Flyway的锁机制

Flyway使用数据库锁机制(locking technology of your database)来协调多个节点,从而保证多套应用程序可同时执migration,而且集群控制也可做配置基于数据库锁机制实现分布式锁有两种,基于数据库表和基于数据库排他锁,Flyway采用的是基于数据库排他锁。

排他锁(Exclusive Locks,简称X锁),又称为写锁、独占锁,在数据库管理上,是锁的基本类型之一。若
事务T对数据对象A加上X锁,则只允许T读取修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放
A上的锁。这就保证了其他事务T释放A上的锁之前不能再读取和修改A

源码如下:

@Override
public <T> T lock(Table table, Callable<T> callable) {
		if (database.isPxcStrict()) {
		return super.lock(table, callable);
}
	return new MySQLNamedLockTemplate(jdbcTemplate,table.toString().hashCode()).execute(callable);
}
@Override
protected void doLock() throws SQLException {
		jdbcTemplate.execute("SELECT * FROM " + this + " FOR UPDATE");
}
private boolean tryLock() throws SQLException {
		return jdbcTemplate.queryForInt("SELECT GET_LOCK(?,10)", lockName) == 1;
}

1.3.3 Flyway连接数据库

flyway使用JDBC连接数据库

private boolean hasUserVariableResetCapability() {
	try {
		jdbcTemplate.queryForStringList(userVariablesQuery);
		return true;
	} catch (SQLException e) {
		LOG.debug("Disabled user variable reset as " + (database.isMariaDB() ? USER_VARIABLES_TABLE_MARIADB :USER_VARIABLES_TABLE_MYSQL)+ "cannot be queried (SQL State: " + e.getSQLState() + ",Error Code: " + e.getErrorCode() + ")");
	return false;
}
}

1.3.4 Flyway的启动速度

耗时主要来源两个方面
(1).Flyway依次读取脚本内容时的IO开销
(2).Flyway计算脚本checksum值的算法开销
对于IO开销而言,每个脚本如果不是涉及大量的数据变更,只是表结构的变更,脚本大小都非常小,可以不考虑。

二、Flyway的使用

接下来进入正题了,flyway该如何使用呢?
以下是Java的使用方式

2.1 添加依赖

<dependency>
	<groupId>org.flywaydb</groupId>
	<artifactId>flyway-core</artifactId>
	<version>6.5.7</version>
</dependency>

2.2 添加配置

java
spring:
  flyway:
    #是否启用
    enabled: true
	# 可以支持多个location,','隔开
	locations: classpath:db/migration
	#是否创建数据表
	validate-on-migrate: true
	# flyway 的 clean 命令删除指定 schema 下的所有 table, 生产务必禁掉。这个默认值false 理论上作为默认配置是不科学的。
	clean-disabled: true
	# 如果数据库不是空表,需要设置true,否则启动报错
	baseline-on-migrate: true
	# 版本控制日志表,默认flyway_schema_history,不同系统建议修改数据
    # table: flyway_schema_history

2.3 创建sql文件

在这里插入图片描述

2.4 启动项目即可

三、Flyway详解

3.1 命令

1.常用命令Migrate, Clean, Info, Validate, Baseline, Repair。

2.Migrate是指把数据库默认数据库迁移到最新版本。

3.Clean这个命令会清除指定库下所有的对象,包括table、view、triggers…,让数据库变成空的状态

4.info用于打印所有Migrations的详细和状态信息

5.Validate是指验证已经应用的Migrations是否有变更,Flyway是默认是开启验证的。

6.Baseline针对已经存在表结构的数据库的一种解决方案,即实现在非空数据库中新建Metadata表,并把Migrations应用到该数据库。

7.Repair操作能够修复Metadata表,该操作在Metadata表出现错误时是非常有用的。

8.Repair会修复Metadata表的错误,通常有两种用途:
移除失败的Migration记录,该问题只是针对不支持DDL事务的数据库。
②重新调整已经应用的Migratons的Checksums值,比如:某个Migratinon已经被应用,但本地进行了修改,又期望重新应用并调整Checksum值,不过尽量不要这样操作,否则可能造成其它环境失败。

3.2 配置行

flyway配置详解
flyway.baseline-description对执行迁移基准版本的描述.
flyway.baseline-on-migrate当迁移发现目标schema非空,而且带有没有元数据的表时,是否自动
行基准迁移,默认false.
flyway.baseline-version开始执行基准迁移时对现有的schema的版本打标签默认值为1.
flyway.check-location检查迁移脚本的位置是否存在,默认false.
flyway.clean-on-validationerror当发现校验错误时是否自动调用clean,默认false.
flyway.enabled是否开启flywary,默认true.
flyway.encoding设置迁移时的编码,默认UTF-8.
flyway.ignore-failed-future-migration当读取数据表时是否忽略错误的迁移,默认false.
flyway.init-sqls当初始化好连接时要执行的SQL.
flyway.locations迁移脚本的位置,默认db/migration.
flyway.out-of-order是否允许无序的迁移,默认false.
flyway.password目标数据库的密码.
flyway.placeholder-prefix设置每个placeholder的前缀,默认${.
flyway.placeholder-replacementplaceholders是否要被替换,默认true.
flyway.placeholder-suffix设置每个placeholder的后缀,默认}.
flyway.placeholders.[placeholder name]设置placeholder的value
flyway.schemas设定需要flywary迁移的schema大小写敏感,默认为连接默认的schema.
flyway.sql-migration-prefix迁移文件的前缀,默认为V.
flyway.sql-migration-separator迁移脚本的文件名分隔符,默认__
flyway.sql-migration-suffix迁移脚本的后缀,默认为.sql
flyway.tableflyway使用的元数据表名,默认为schema_version
flyway.target迁移时使用的目标版本,默认为latest version
flyway.url迁移时使用的JDBC URL,如果没有指定的话,将使用配置的主数据源
flyway.user迁移数据库的用户
flyway.validate-on-migrate迁移时是否校验,默认为true.

3.3 执行方式

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

3.4 sql脚本命名规则

1.仅需要执行一次的,以大写“V”开头,V+版本后(版本号间的数字以“.” 或者“ _ ”分隔开,“ _ ”会自动编译
成 “ . ” )+” __“+文件描述+后缀名
2.需要执行多次的,以大写“R”开头,命名如R__clean.sql ,R的脚本只要改变了就会执行,R不带版本号
3.V开头的比R开头的优先级要高。

前缀用于版本控制(可配置)、撤消(可配置)和可重复迁移(可配置)VUR)
版本:带有点或下划线的版本可根据需要分隔任意数量的部分(不适用于可重复的迁移)
分隔符:(两个下划线)(可配置)__)
说明:下划线或空格分隔单词
后缀:(可配置.sql)
(可选)版本控制 SQL 迁移还可以省略分隔符和说明

在这里插入图片描述

四 开发时注意事项

1.报错后需要删除flyway_schema_history中记录,否则启动失败
2.V的优先级高于R,假如三个V迁移脚本和一个R(无论新建还是修改)一起执行,其中一个V报错,则V会
全部执行完成且记录到flyway_schema_history中,而R不执行且不记录,删除表中报错记录后,查询
动,则执行原错误V和未执行的R
3.多个要执行的R中,如果出现了其中一个出现了错误,则在其后的R都不执行
4.R的执行顺序根据命名来进行排序
5.一个文件中ddl并不由一个事务管理,比如创建三个表,中间创建语句报错,则第一个表还是会创建
成功并且提交事务
6.已经执行过的迁移文件(V)不能修改,否则报错。
7.同一个迁移文件下同表内DDL无法回滚,DML可回滚, 从报错点开始不往下执行,Flyway使用数据库锁
机制
8.版本号相同会报错(Found more than one migration with version 1.0.0.9)
9.同一个迁移文件下假设都是dml,那么如果中间出现错误,所有的dml语句都会回滚
10.删除sql文件后启动会报错,报错如下:

If you removed this migration intentionally, run repair to mark the migration as
deleted.

五、部署上线时注意事项

  1. 如果不手动创建元数据表,则需要进行以下配置,用于自动创建
    validate-on-migrate: true
    If you removed this migration intentionally, run repair to mark the migration as
    deleted.
  2. 如果数据库不是空表,则需进行以下配置,否则启动报错
    baseline-on-migrate: true
  3. clean命令会删除数据库中所有表,包括数据,结构等,这是不合理的,所以需要进行以下配置
    clean-disabled: true (该配置由于默认值合理,所以在V9版本中修改默认值false为true)
  4. 使用flyway要注意版本兼容问题springboot与flyway,flyway与数据库版本,否则启动报错
  5. 如果启动的时候像忽略某些迁移文件,可进行以下参数配置
    baseline-version=20210809,以忽略 20210809 版本以及之前的所有 migration
  6. 多人开发中,如果一个人提交V2一个人提交V1,而V2先入库执行了,那么V1入库就不会执行,如
    果需要执行则需进行如下配置,但是不建议这么做
    out-of-order=true

六、 支持的数据库版本

目前支持mysql5.7的社区版为7.15.0,支持mysql8.0的版本是8.2.0,8.2.1移除mysql支持,如文档
文:

Extract MySQL code to plugin. This will need to be added as a new dependency.

flyway的8.2.1版本移除mysql解决方案,增加依赖

<dependency>
	<groupId>org.flywaydb</groupId>
	<artifactId>flyway-mysql</artifactId>
</dependency>

七、总结

Flyway的引用确实方便了后续我们团队的数据库版本管理,但各个团队使用场景皆有不同,所以本文只供想要学习Flyway的朋友借鉴,另:flyway的社区版同专业版相比也是有一些区别的,类似下面的两个方面,所以在选择Flyway时需考虑引入对整体架构的提升,本文分享这里结束,感谢大家耐心观看。
社区版目前不支持版本回退
社区版本没有任务队列异步任务的支持,所以在大量变更时略有风险,尽量拆分

原文地址:https://blog.csdn.net/Jiao1225/article/details/129590660

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_6409.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注