一、Flyway简介
Flyway是一款开源的数据库迁移工具,可以管理和版本化数据库架构。通过Flyway,可以跟踪数据库的变化,并将这些变化作为版本控制的一部分。Flyway支持SQL和NoSQL数据库,并且可以与现有的开发流程无缝集成,如持续集成(CI)和持续部署(CD)。
二、Flyway主要特性
Flyway的主要特性包括:
- 版本化迁移(Versioned Migrations):通过一系列的SQL脚本逐步更新数据库架构,每个迁移脚本都有一个唯一的版本号,例如
V1__Initial_setup.sql
。当Flyway运行时,它会检查数据库中的flyway_schema_history
表,以确定哪些迁移脚本已经执行过了。如果发现有未执行的迁移脚本,Flyway将按照版本号的顺序执行它们。 - 回退迁移(Undo Migrations):是指在某些情况下,可能需要将数据库回滚到一个先前的状态。Flyway并没有内置的回退机制,但它提供了基础设施,允许你在迁移脚本中定义回退逻辑。通常是通过在迁移脚本中指定一个相反的迁移脚本来实现的。例如,如果你有一个迁移脚本
V2__Add_new_column.sql
,你可以创建一个对应的回退脚本R2__Drop_new_column.sql
,其中R2
表示这是一个回退脚本。在需要回滚时,Flyway会执行相应的回退脚本,将数据库回滚到上一个稳定的状态。 - 可重复迁移(Repeatable Migration):是与版本化迁移不同的另一种类型的迁移,它不依赖于版本号。这种迁移脚本通常用于那些不需要跟踪版本的变更,比如对数据库性能调优的脚本。Flyway会简单地将这些脚本视为一组独立的更改,并在每次运行时执行它们。
- 多数据库支持:Flyway支持多种关系型数据库,如MySQL、Oracle、PostgreSQL等,使得在不同数据库间迁移变得容易。
- 自动化迁移:Flyway可以在应用程序启动时自动执行迁移脚本,或者通过命令行手动执行,提高了迁移的效率和可靠性。
- 集成到开发流程:Flyway可以集成到持续集成(CI)和持续部署(CD)流程中,确保数据库结构随着应用程序的发展而保持同步。
三、Flyway的工作流程
Flyway的设计哲学是约定优于配置,这意味着它遵循一些预定义的规则来简化数据库迁移的过程。下面是Flyway的基本工作流程:
- 初始化:当你首次运行Flyway时,它会根据配置在数据库中创建一个名为
flyway_schema_history
的表,这个表用来记录所有的迁移活动,包括迁移的版本号、描述、执行的SQL文件名、执行时间和是否成功等信息。 - 扫描迁移脚本:Flyway会扫描指定的目录(通常是
classpath:db/migration
)以查找迁移脚本。这些脚本通常命名为V<version>__<description>.sql
,其中<version>
是迁移的版本号,<description>
是对迁移的简短描述。 - 比较版本号:Flyway会比较数据库中的
flyway_schema_history
表记录的当前版本号与现有迁移脚本中的版本号。如果存在未执行的迁移脚本,Flyway将会执行它们。 - 执行迁移:对于每个需要执行的迁移脚本,Flyway会将其作为一个事务执行。如果在执行过程中出现错误,Flyway会回滚整个事务,并记录错误信息。
- 记录迁移结果:一旦迁移脚本执行完毕,无论是成功还是失败,Flyway都会在flyway_schema_history表中记录下迁移的结果。
- 重复执行:如果需要,你可以重复执行Flyway的迁移过程,以应用新的迁移脚本。Flyway会识别哪些迁移已经被执行过,并跳过它们。
四、与SpringBoot项目整合
4.1 添加依赖
到项目的pom文件中添加Flyway的依赖包。
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId>
<version>8.5.13</version>
</dependency>
4.2 修改配置
到项目的application.yaml文件中添加Flyway的配置信息。
sping:
flyway:
#是否开启flyway,默认true
enabled: true
#当迁移时发现目标schema非空,而且没有元数据的表时,(即迭代中项目应为true)是否自动执行基准迁移,默认false.
baseline-on-migrate: true
# 是否允许无序运行迁移, 默认false,建议开发环境开启,生成环境关闭
out-of-order: false
#设定SQL脚本的目录,可以配置多个,比如为classpath:db/migration,filesystem:/sql-migrations,默认classpath:db/migration
locations:
- classpath:db/migration
常用配置项如下:
- spring.flyway.enabled: 是否启用Flyway,默认为true。
- spring.flyway.table: Flyway元数据表的名称,默认为flyway_schema_history。
- spring.flyway.encoding: 迁移脚本文件的编码,默认为UTF-8。
- spring.flyway.validate-on-migrate: 迁移时是否进行验证,默认为true。
- spring.flyway.check-location: 是否检查迁移脚本的位置是否存在,默认为true。
- spring.flyway.clean-disabled: 是否禁用Flyway的clean操作,默认为false。
- spring.flyway.baseline-on-migrate: 当迁移时发现目标schema非空,并且没有元数据的表时,是否自动执行基准迁移,默认为false。
- spring.flyway.baseline-version: 开始执行基准迁移时对现有schema的版本打标签,默认为1。
- spring.flyway.locations: 迁移脚本的位置,默认为classpath:db/migration。
- spring.flyway.sql-migration-prefix: 迁移文件的前缀,默认为V。
- spring.flyway.sql-migration-suffix: 迁移脚本的后缀,默认为.sql。
- spring.flyway.out-of-order: 是否允许无序的迁移,默认为false。
- spring.flyway.schemas: 需要Flyway迁移的schema,默认为连接默认的schema。
4.3 编写sql脚本文件
sql脚本文件名称要符合flyway规范,命名规则如下:
- 版本迁移脚本(Versioned Migrations):脚本文件名的前缀通常是
V
,后跟版本号(版本号之间可以用点.
或下划线_
分隔),版本号后面是__
双下划线的分隔符,分隔符后面是文件描述,最后是文件后缀名。例如:V1__Initial_Setup.sql
、V1.1.2__Initial_Setup.sql
、V1.1.2_1__Initial_Setup.sql
。 - 回退迁移(Undo Migrations):脚本文件名的前缀为
U
,前缀后面部分与版本迁移脚本的文件名相同。例如:U1__Initial_Setup.sql
、U1.1.2__Initial_Setup.sql
、U1.1.2_1__Initial_Setup.sql
。 - 可重复迁移脚本(Repeatable Migrations):脚本文件名的前缀是
R
,由于不依赖版本号,所以后面可以直接跟分隔符和脚本名称。例如R__truncate_user_dml.sql
。
默认情况下sql脚本文件都放在src\main\resources\db\migration
下:
4.4 启动项目自动完成脚跟更新
项目启动日志中打印出Flyway 的脚本执行信息如下:
五、错误总结
Spring Boot版本是2.5.12,MySQL用的是8.2。
-
Unsupported Database: MySQL 8.2
这个问题是由于开始用的Flyway 依赖是flyway-core
的8.5.13版本,后面换成flyway-mysql
的8.5.13版本解决问题。 -
Validate failed: Migrations have failed validation
(1)Either revert the changes to the migration, or run repair to update the schema history.
这个问题是由于脚本已经被migration 过了,后面又对这个脚本做了修改所导致的。所以已经被migration 过脚本文件一定不要再去修改
,实在要改的话重新写个脚本文件去修改。这里解决问题是删掉flyway_schema_history表中之前执行过的记录
,这样重新再启动的时候Flyway 校验这个脚本时找不到之前执行过的记录,就会认为这是个全新的脚本不会与之前执行过的脚本有冲突,才会再次执行这个脚本。其实这样改还不是很好,因为这个脚本的的确确已经执行过一次,如果这个脚本是个添加一条记录的语句,你后面只是在这个语句中多加了个字段,然后再次去执行,那结果就是再新增一条类似的数据,而我们的本意其实只是想改动之前的数据,所以如果不小心改动了之前已经migration 过的脚本,最好连同这个脚本执行过的sql记录也一起删掉
。
(2)Please remove any half-completed changes then run repair to fix the schema history.
这个问题是由于在项目启动时Flyway 执行脚本出错,但是flyway_schema_history
表中已经记录了这次脚本的migration失败的操作, 当你修改完脚本后再次启动项目时,发现flyway_schema_history
表中有过这个脚本的migration操作,从而导致校验不通过。这种情况只需要把flyway_schema_history表中这个脚本之前失败的记录删除
重启项目就可以,因为之前执行该脚本时,该脚本的sql报错并没有对数据库进行实际的操作,所以也就不用去数据库删除之前这个脚本操作产生的实际数据了。 -
Flyway failed to initialize: none of the following migration scripts locations could be found
这个问题是由于没找到sql脚本文件,可能是设置指定存放sql脚本的目录出错或者目录中压根没有脚本文件。我这个是没有脚本文件,项目启动时报的错,随便添加个空的脚本文件后就能正常启动了。