1. 简介

本文将深入探讨Flyway的核心概念,以及如何利用该框架可靠、轻松地持续重构应用程序的数据库架构。同时,我们将演示一个使用Maven Flyway插件管理内存H2数据库的实例。

Flyway通过迁移脚本将数据库从一个版本更新到下一个版本。我们可以使用特定数据库语法的SQL编写迁移脚本,或使用Java实现高级数据库转换。

迁移脚本分为两种类型:版本化迁移和可重复迁移。前者具有唯一版本号且仅执行一次,后者没有版本号,每当校验和发生变化时就会重新执行。

在单次迁移运行中,可重复迁移总是在待处理的版本化迁移执行完成后才应用,并按描述顺序执行。单个迁移中的所有语句在单个数据库事务中运行。

本文主要聚焦如何使用Maven插件执行数据库迁移。

2. Flyway Maven插件

要在Maven中安装Flyway插件,在pom.xml中添加以下插件定义:

<plugin>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-maven-plugin</artifactId>
    <version>10.7.1</version> 
</plugin>

最新插件版本可在Maven中央仓库获取。

该Maven插件可通过四种方式配置,下面我们逐一介绍。完整可配置属性列表请参考官方文档

2.1. 插件配置

直接在pom.xml的插件定义中通过<configuration>标签配置

<plugin>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-maven-plugin</artifactId>
    <version>10.7.1</version>
    <configuration>
        <user>db_user</user>
        <password>secure_password</password>
        <schemas>
            <schema>app_schema</schema>
        </schemas>
        ...
    </configuration>
</plugin>

2.2. Maven属性

通过在pom中指定Maven属性配置插件

<project>
    ...
    <properties>
        <flyway.user>db_user</flyway.user>
        <flyway.password>secure_password</flyway.password>
        <flyway.schemas>app_schema</flyway.schemas>
        ...
    </properties>
    ...
</project>

2.3. 外部配置文件

在单独的*.conf*文件中提供插件配置

flyway.user=db_user
flyway.password=secure_password
flyway.schemas=app_schema
...

默认配置文件名为flyway.conf,加载路径包括:

  • installDir/conf/flyway.conf
  • userhome/flyway.conf
  • workingDir/flyway.conf

编码由flyway.encoding属性指定(默认为UTF-8)。

若使用自定义名称(如customConfig.conf),需在Maven命令中显式指定:

$ mvn -Dflyway.configFiles=customConfig.conf

2.4. 系统属性

所有配置属性均可作为系统属性在命令行指定

$ mvn -Dflyway.user=db_user -Dflyway.password=secure_password 
  -Dflyway.schemas=app_schema

配置优先级顺序(从高到低):

  1. 系统属性
  2. 外部配置文件
  3. Maven属性
  4. 插件配置

3. 迁移示例

本节演示使用Maven插件将数据库架构迁移到内存H2数据库的完整步骤,采用外部文件配置Flyway。

3.1. 更新POM

首先添加H2依赖:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

最新驱动版本可在Maven中央仓库查看。同时按前述方式添加Flyway插件。

3.2. 使用外部文件配置Flyway

在项目根目录创建myFlywayConfig.conf文件:

flyway.user=db_user
flyway.password=secure_password
flyway.schemas=app-db
flyway.url=jdbc:h2:mem:DATABASE
flyway.locations=filesystem:db/migration

该配置指定:

  • 迁移脚本位于db/migration目录
  • 使用db_usersecure_password连接内存H2实例
  • 数据库架构为app-db

⚠️ 实际使用时需替换为真实的数据库凭据和URL。

3.3. 定义首次迁移

Flyway遵循以下迁移脚本命名规范

<Prefix><Version>__<Description>.sql

其中:

  • <Prefix>:默认为V,可通过flyway.sqlMigrationPrefix属性修改
  • <Version>:迁移版本号,主次版本可用下划线分隔(如1_0),版本号必须从1开始
  • <Description>:迁移描述文本,与版本号用双下划线分隔

示例:V1_1_0__add_user_table.sql

在项目根目录创建db/migration目录,添加迁移脚本V1_0__create_employee_schema.sql

CREATE TABLE IF NOT EXISTS `employee` (
    `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `name` varchar(20),
    `email` varchar(50),
    `date_of_birth` timestamp
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

3.4. 执行迁移

在项目根目录执行Maven命令:

$ mvn clean flyway:migrate -Dflyway.configFiles=myFlywayConfig.conf

成功执行后,数据库架构如下:

employee:
+----+------+-------+---------------+
| id | name | email | date_of_birth |
+----+------+-------+---------------+

可重复此流程执行更多迁移。

3.5. 定义并执行第二次迁移

创建第二个迁移文件V2_0__create_department_schema.sql

CREATE TABLE IF NOT EXISTS `department` (
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(20)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8; 

ALTER TABLE `employee` ADD `dept_id` int AFTER `email`;

执行相同迁移命令后,数据库架构更新为:

employee:
+----+------+-------+---------+---------------+
| id | name | email | dept_id | date_of_birth |
+----+------+-------+---------+---------------+
department:
+----+------+
| id | name |
+----+------+

✅ 通过以下命令验证迁移结果:

$ mvn flyway:info -Dflyway.configFiles=myFlywayConfig.conf

4. 在IntelliJ IDEA中生成版本化迁移

手动编写迁移脚本耗时费力,我们可以基于JPA实体自动生成迁移脚本。通过IntelliJ IDEA的JPA Buddy插件可实现此功能。

要生成差异版本化迁移,只需安装插件并在JPA结构面板中调用相应操作。

选择源(数据库或JPA实体)和目标(数据库或数据模型快照)后,JPA Buddy将自动生成迁移脚本

flyway migration generation jpa

JPA Buddy的另一优势是支持定义Java与数据库类型映射,并能正确处理Hibernate自定义类型和JPA转换器。

5. 在Spring Boot中禁用Flyway

某些场景下需要禁用Flyway迁移,例如测试时通常基于实体生成数据库架构。此时可在test配置文件中禁用Flyway。

5.1. Spring Boot 1.x

application-test.properties中设置:

flyway.enabled=false

5.2. Spring Boot 2.x, 3.x

新版本中属性名改为:

spring.flyway.enabled=false

5.3. 空的FlywayMigrationStrategy

若需禁用自动迁移但保留手动触发能力,上述属性配置不适用(因会禁用整个Flyway自动配置)。

更优雅的方案是实现空的FlywayMigrationStrategy

@Configuration
public class EmptyMigrationStrategyConfig {

    @Bean
    public FlywayMigrationStrategy flywayMigrationStrategy() {
        return flyway -> {
            // 空实现,不执行任何操作
        };
    }
}

这将禁用启动时的自动迁移,但仍可手动触发:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ManualFlywayMigrationIntegrationTest {

    @Autowired
    private Flyway flyway;

    @Test
    public void skipAutomaticAndTriggerManualFlywayMigration() {
        flyway.migrate(); // 手动执行迁移
    }
}

6. Flyway工作原理

为跟踪已应用的迁移及其执行时间,Flyway在数据库中创建元数据表(默认为SCHEMA_VERSION)。该表还记录迁移脚本的校验和及执行状态。

框架执行以下步骤处理数据库架构演进:

  1. 检查数据库中的元数据表,不存在则创建
  2. 扫描应用类路径下的可用迁移脚本
  3. 将迁移脚本与元数据表对比,忽略版本号≤当前标记版本的脚本
  4. 将剩余脚本标记为待处理迁移,按版本号排序后依次执行
  5. 每个迁移执行后更新元数据表

7. 常用命令

Flyway提供以下基础命令管理数据库迁移:

  • **info**:打印数据库架构当前状态/版本,显示待处理/已应用的迁移、执行状态和时间
  • **migrate**:将数据库架构迁移到最新版本,扫描并应用待处理迁移
  • **baseline**:为现有数据库设置基线,排除所有迁移(包括基线版本)。帮助在现有数据库中启用Flyway
  • **validate**:验证当前数据库架构与可用迁移的一致性
  • **repair**:修复元数据表
  • clean:删除配置架构中的所有对象❌(切勿在生产环境使用

8. 总结

本文介绍了Flyway的工作原理,以及如何利用该框架可靠地重构应用程序数据库。完整示例代码可在GitHub仓库获取。


原始标题:Database Migrations with Flyway