一、flyway介绍

1.1、什么是flyway

Flyway 是一款开源的数据库版本管理工具。它可以很方便的在命令行中使用,或者在Java应用程序中引入,用于管理我们的数据库版本。

在项目或产品中,很难一开始就把业务理清楚,把数据库表设计好,因此数据表也会在迭代周期不断迭代。在Java应用程序中使用Flyway,能快速有效地用于迭代数据库表结构,并保证部署到测试环境或生产环境时,数据表都是保持一致的。

1.2、为什么要使用flyway

我们有多个测试、生产环境,却缺乏统一的sql版本管理,导致每个环境重新部署发布时很难判断有哪些脚本要执行,容易出现某个环境未执行脚本导致项目运行问题,flyway可以替我们管理sql脚本文件版本,并记住每个环境有哪些脚本已经执行过,还需要执行哪些脚本。

1.3、脚本名称约定

sql脚本名称约定格式:V + 版本号 + 双下划线(__) + 描述 + 结束符(.sql)

1.4、版本控制原理

主要是通过对比flyway_schema_history表中 versionchecksum,来判断文件是否存在与被修改过,来执行版本控制的。

1.5、flyway工作流程

1、项目启动,应用程序完成数据库连接池的建立后,Flyway自动运行。

2、初次使用时,Flyway会创建一个flyway_schema_history表,用于记录sql执行记录。

3、Flyway会扫描项目指定路径下(默认是classpath:db/migration)的所有sql脚本,与flyway_schema_history表脚本记录进行比对。如果数据库记录执行过的脚本记录,与项目中的sql脚本不一致,Flyway会报错并停止项目执行。

4、如果校验通过,则根据表中的sql记录最大版本号,忽略所有版本号不大于该版本的脚本。再按照版本号从小到大,逐个执行其余脚本。

二、开发注意事项

1、脚本文件命名V + 版本号 + 双下划线(__) + 描述 + 结束符(.sql),注意是双下划线,另外版本号必须按顺序添加,不可以添加比已经执行过的脚本文件更早的版本号。

2、脚本文件如果已经执行过,便不要在进行任何更改(否则无法通过校验,常见错误2),如果需要修改请通过新增一个新的sql脚本文件来达成。

3、注意脚本文件的正确性,一定要保证脚本的正确

如果脚本有错误导致执行失败,这时脚本改正后还不能直接执行,如果直接执行会发生常见错误1,这是因为flyway在版本管理flyway_schema_history表中收录了改正前的脚本,这时需要把改成前的版本清理掉才可以执行改正后的sql脚本,请找到success为0的版本进行删除,删除后可以执行改正后的sql脚本

4、通常不建议手动更改flyway_schema_history表的数据,因为表中的数据是Sql版本管理的依据。

三、运维注意事项

1、从A数据库还原到B数据库要保证还原后B的表结构和A完全一致,表不能多也不能少(还原后B数据库多一张表或少一张表时有发生),每张表的字段必须和A数据库完全一致。

2、除日志表外,从A数据库还原到B数据库要保证还原后B数据库每张表的数据建议与A数据库完全一致。

3、如果是新创建的环境,注意不要漏掉nacos配置(yaml格式文件对缩进有严格要求,请参考yaml语法)

spring:
  flyway:
      # 是否启用flyway
      enabled: true
      # 迁移sql脚本文件存放路径,默认classpath:db/migration
      # locations: classpath:db/migration
      # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表
      baseline-on-migrate: true
      # 允许存储占位符${}
      placeholderReplacement: false

四、常见错误与排查方法

4.1、sql查询版本管理记录

如果启动失败,首先查看flyway_schema_history是否有success为0的记录,如果有,查看script字段即执行失败的sql脚本文件名,找到这个文件(运维查看sql脚本路径xxx-system-1.0.0.jar\BOOT-INF\classes\db\migration ),检查这个sql脚本执行失败的原因,如果运维不能确定失败原因,请把文件名发到开发群里,由sql文件提交者排查执行失败原因。

SELECT * FROM SLSPD."flyway_schema_history" ORDER BY "version" DESC;

字段解释:

installed_rank:执行序号

version:版本

script:sql脚本文件

checksum:类似文件md5值,flyway用来判断文件是否被修改

success:是否执行成功,1成功,0失败

如果手写sql查询版本管理记录提示表或视图不存在,这是因为flyway_schema_history表名是小写的,请在表名上加双引号(oracle表和字段有大小写的区别,oracle默认是大写,如果我们用双引号括起来的就区分大小写,如果没有,系统会自动转成大写)。

4.2、查看system日志

以xx服务器为例

进入日志目录:

cd /xxx/logs

查看最后400行日志:

tail -400f xxx-system.log

如果system启动失败,日志中有FlywayException异常信息,查询flyway_schema_history表是否有success为0的记录,如果有,按照4.1进行判断,如果没有,请将异常信息发到开发群中,可能是开发修改了已经执行成功的sql脚本文件。

4.3、常见错误1:

sql脚本有错误,执行失败修改后重新执行报错:

nested exception is org.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: Validate failed: 
Detected failed migration to version 20220207.3 (test delete)

需要手动修复,找到对应的约束进行删除:

DELETE FROM SPDCLOUD."flyway_schema_history" WHERE "installed_rank"=xxx;

4.4、常见错误2:

已经执行过的脚本被改动,导致校验失败

nested exception is org.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: Validate failed: 
Migration checksum mismatch for migration version 20220207.1
-> Applied to database : -335589342
-> Resolved locally    : -725714856

还原该脚本可以解决

五、某些特殊需求的特殊处理

5.1、修改执行过的脚本

如果因为某些特定原因必须修改已经执行过的脚本,不修改不行,记住修改后脚本的checksum,手动覆盖到每一个环境的flyway_schema_history版本记录中。

5.2、删除执行过的脚本

由于特殊原因必须删除已经执行过的脚本,例如sql脚本文件过多,想要清理,建议在所有环境同步更新后,再删除sql脚本文件,并对应删除flyway_schema_history里的版本记录。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐