一、前言一般在我们开发项目的时候经常会更新数据库表的字段如果同事 a 添加了表字段没有及时给同事 b sql 脚本,可能同事 b 的代码运行就会报错而且随着时间的推移sql 脚本越来越多项目上线的时候整理起来就很费时间,所以就有大佬级别的人物创造了 Flyway 这个数据库版本管理工具。Flyway 是一款开源的数据库版本管理工具它更倾向于规约优于配置的方式。Flyway 可以独立于应用实现管理并跟踪数据库变更支持数据库版本自动升级并且有一套默认的规约不需要复杂的配置Migrations 可以写成 SQL 脚本也可以写在 Java 代码中不仅支持 Command Line 和 Java API还支持 Build 构建工具和 Spring Boot 等同时在分布式环境下能够安全可靠地升级数据库同时也支持失败恢复等。二、Flyway介绍2.1 主要特性1.普通 SQL纯 SQL 脚本(包括占位符替换)没有专有的XML格式没有锁定2.无限制使用 Java 代码来进行一些高级数据操作3.零依赖只需运行在 Java6(及以上)和数据库所需的 JDBC 驱动4.约定优于配置迁移时自动查找系统文件和类路径中的 SQL 文件或 Java 类5.高可靠性在集群环境下进行数据库升级是安全可靠的6.云支持完全支持 Microsoft SQL Azure, Google Cloud SQL App Engine、Heroku Postgres 和 Amazon RDS7.自动迁移使用 Flyway 提供的 API让应用启动和迁移同时工作8.快速失败损坏的数据库或失败的迁移可以防止应用程序启动9.数据库清理在一个数据库中删除所有的表、视图、触发器而不是删除数据库本身2.2 运行原理当 Flyway 连接数据库中的 schema 后会先检查是否已存在 flyway_schema_history 表如果没有则创建。该表用于跟踪数据库的状态如数据迁移的版本迁移成功状态等信息。当 flyway_schema_history 存在后Flyway 会扫描文件系统或应用中的 classpath 目录的数据迁移文件然后根据它们的版本号进行按序迁移如下图由于 flyway_schema_history 表中记录了迁移的版本号如果文件的版本号小于或等于标记为当前版本的版本号则忽略它们不执行。在实际使用中flyway有两种方式执行一种是构建项目的时候执行一种是项目启动的时候执行。上边描述的内容或许对读者来说还不够直观那么下面我们就开始进行实战演练。三、构建实战环境mysql-5.7.30springboot 2.3.5.RELEASE新建一个 Maven 项目。3.1 添加依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.flywaydb/groupIdartifactIdflyway-core/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependency注意:如果构件项目的时候执行Flyway那么就必须引入spring-boot-starter-jdbc依赖。3.2 配置数据迁移文件在项目的 src/main/resources 下创建 db/migration 目录该目录下放置需要数据迁移的文件。数据迁移文件默认名称格式为V[version]__[name].sql。注意名称中[version]和[name]之间是两个下划线本次测试新建名为 V0.1.0__init_table.sql 的文件内容如下:USEFLYWAYDB;DROPTABLEIFEXISTSuser;CREATETABLEuser(idBIGINT(20)NOTNULLCOMMENT主键ID,nameVARCHAR(30)NULLDEFAULTNULLCOMMENT姓名,ageINT(11)NULLDEFAULTNULLCOMMENT年龄,emailVARCHAR(50)NULLDEFAULTNULLCOMMENT邮箱,PRIMARYKEY(id));我们再新建一个名为 V0.1.1__init_data.sql 文件内容如下INSERTINTOuser(id,name,age,email)VALUES(1,Jone,18,test1baomidou.com),(2,Jack,20,test2baomidou.com),(3,Tom,28,test3baomidou.com),(4,Sandy,21,test4baomidou.com),(5,Billie,24,test5baomidou.com);版本 1 数据迁移的内容是创建一张 user 表。3.3 配置application.ymlspring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/flywaydb?createDatabaseIfNotExisttrueserverTimezoneUTCuseUnicodetruecharacterEncodingutf-8useSSLtrueusername:rootpassword:123456flyway:enabled:true# 禁止清理数据库表table:flywayinit#修改原数据表名默认为schema_version编译项目结果如下图图中数据库 flywaydb 中创建了 flywayinit 表和 user 表数据成功迁移到指定数据库中。当系统升级时又需要做数据迁移我们只需在 db/migration 目录下再放置新版本的 sql 文件即可。版本 0.1.1 的数据迁移内容是往 user 表中插入 3 条数据。上面我们在application.yml配置了flyway初始化的数据库其实也可以配置好多相关参数具体如下配置项含义flyway.baseline-description对执行迁移时基准版本的描述.flyway.baseline-on-migrate当迁移时发现目标schema非空而且带有没有元数据的表时是否自动执行基准迁移默认false.flyway.baseline-version开始执行基准迁移时对现有的schema的版本打标签默认值为1.flyway.check-location检查迁移脚本的位置是否存在默认false.flyway.clean-on-validation-error当发现校验错误时是否自动调用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的valueflyway.schemas设定需要flywary迁移的schema大小写敏感默认为连接默认的schema.flyway.sql-migration-prefix迁移文件的前缀默认为V.flyway.sql-migration-separator迁移脚本的文件名分隔符默认__flyway.sql-migration-suffix迁移脚本的后缀默认为.sqlflyway.tableflyway使用的元数据表名默认为schema_versionflyway.target迁移时使用的目标版本默认为latest versionflyway.url迁移时使用的JDBC URL如果没有指定的话将使用配置的主数据源flyway.user迁移数据库的用户名flyway.validate-on-migrate迁移时是否校验默认为true.四、启动方式实践4.1 引入依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.flywaydb/groupIdartifactIdflyway-core/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scope/dependency4.2 修改application.ymlspring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/flywaydb?createDatabaseIfNotExisttrueserverTimezoneUTCuseUnicodetruecharacterEncodingutf-8useSSLtrueusername:rootpassword:1234564.3 编码创建配置类FlywayConfig.javaConfigurationpublicclassFlywayConfig{Value(${spring.datasource.url})privateStringurl;Value(${spring.datasource.username})privateStringusername;Value(${spring.datasource.password})privateStringpassword;PostConstructpublicvoidmigrate(){FlywayflywayFlyway.configure().dataSource(url,username,password).table(flyway_init_table).load();// 创建 flyway_schema_history 表//flyway.baseline();// 删除 flyway_schema_history 表中失败的记录//flyway.repair();// 检查 sql 文件//flyway.validate();// 执行数据迁移flyway.migrate();// 删除当前 schema 下所有表//flyway.clean();}}在构建flyway的时候构件方法和配置中的配置项类似。4.4 启动测试启动项目结果如下图