Flyway 是一款开源的,基于 Java 实现的数据库内容变更控制工具。它提供了 CLI、Java API、Maven/Gradle Plugin 等多种方式方便开发人员将数据库的表结构改动、内容变动以可追溯的代码形式进行管理和部署。Flyway 支持包括大多数主流的关系型数据库:MySQL、SQL Server、Oracle Database、PostgreSQL、SQLite、TiDB、MariaDB 等,对于 MongoDB 的支持尚在预览阶段(更推荐 Mongock),同类竞品有 Liquibase,但 Liquibase 的使用相比 Flyway 更复杂,有额外的概念作为学习成本。
遵循 SpringBoot 广为人知的约定大于配置,Spring 官方提供了 Flyway 的自动配置实现。
全限定类名 org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
会在检测到以下几种状态下实现自动配置:
- 存在
Flyway
类 (即 org.flywaydb.core.Flyway
)
- 满足
FlywayDataSourceCondition
类中的 Bean 或 Properties 条件,其实就是 DataSource
和数据库 URL 等连接配置存在
- 存在
spring.flyway.enabled=true
属性配置
对于 MySQL 而言,除了必须的 JDBC 依赖之外,需要引入 Flyway 自身依赖,SpringBoot 已经在 pom 中声明过版本号,因此此处无需额外定义版本字段:
具体使用有两种方式:
- 原生 SQL
- Java API
Flyway 会基于默认配置的文件夹路径 classpath:db/migration 发现版本变更文件或实现类。
VERSION
可使用包含小数点、下划线的字符串版本,DESCRIPTION
则是简单的描述文本。中间的分割符是两个下划线。可通过 spring.flyway 配置自定义前后缀。
V{VERSION}__{DESCRIPTION}.sql
文件需要存放在 src/main/resources/db/migration 文件夹下; Java 类则需要定义包名 db.migration
并且继承父类 BaseJavaMigration
,重写如下方法:
按照官方的写法,我们就可以在 migrate()
方法中去用 Java 代码实现数据库内容版本变动了,但是这里有一个缺点,那就是我们在 Spring 环境下无法针对 V{VERSION}__{DESCRIPTION}.java
进行依赖注入,只能尝试通过原生 JDBC 的方式、静态方法等去写比较朴素的 SQL 实现,而不能充分成分利用现有的 DAO 接口来做业务数据的更新。因此需要自定义配置 Flyway。
由于 Flyway 的配置基于这种手动配置,因此需要在 SpringBoot 启动类上排除原有的自动配置类,以防止自动配置存在加载冲突。
最后,定义一个 Component Bean 去实现 BaseJavaMigration
:
这样,所有的迁移类都可以方便地使用依赖注入来愉快地做 CRUD 了。经过实践,Flyway 会在数据库连接配置后、HTTP 服务暴露(也就是 Servlet 容器监听端口)前同步地执行完所有迁移,因此无需担心执行时机影响线上服务。