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
配置优先级顺序(从高到低):
- 系统属性
- 外部配置文件
- Maven属性
- 插件配置
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_user和secure_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将自动生成迁移脚本:
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
)。该表还记录迁移脚本的校验和及执行状态。
框架执行以下步骤处理数据库架构演进:
- 检查数据库中的元数据表,不存在则创建
- 扫描应用类路径下的可用迁移脚本
- 将迁移脚本与元数据表对比,忽略版本号≤当前标记版本的脚本
- 将剩余脚本标记为待处理迁移,按版本号排序后依次执行
- 每个迁移执行后更新元数据表
7. 常用命令
Flyway提供以下基础命令管理数据库迁移:
- **
info
**:打印数据库架构当前状态/版本,显示待处理/已应用的迁移、执行状态和时间 - **
migrate
**:将数据库架构迁移到最新版本,扫描并应用待处理迁移 - **
baseline
**:为现有数据库设置基线,排除所有迁移(包括基线版本)。帮助在现有数据库中启用Flyway - **
validate
**:验证当前数据库架构与可用迁移的一致性 - **
repair
**:修复元数据表 clean
:删除配置架构中的所有对象❌(切勿在生产环境使用)
8. 总结
本文介绍了Flyway的工作原理,以及如何利用该框架可靠地重构应用程序数据库。完整示例代码可在GitHub仓库获取。