Flyway:Java 数据库版本控制迁移
xml org.flywaydb flyway-maven-plugin 9.22.3 jdbc:mysql://localhost:3306/mydb root secret
- **Gradle** 在 `build.gradle` 中加入:
```groovy
plugins {
id 'org.flywaydb.flyway' version '9.22.3'
}
flyway {
url = 'jdbc:mysql://localhost:3306/mydb'
user = 'root'
password = 'secret'
}
方式三:Spring Boot 自动配置
Spring Boot 对 Flyway 提供了开箱即用的支持。只需在 application.yml 中配置数据源和 Flyway 基础选项:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: user
password: pass
flyway:
enabled: true
locations: classpath:db/migration
同时,在 src/main/resources/db/migration 目录下放置迁移脚本,应用启动时便会自动执行迁移。
迁移脚本的命名规则
Flyway 通过严格的命名约定来识别脚本版本、顺序和功能。一个标准的 SQL 迁移文件名格式为:
V<版本号>__<描述>.sql
例如:
V1__Create_person_table.sql
V2__Add_age_column.sql
V3.1__Seed_person_data.sql
命名要点:
- 前缀:
V代表版本迁移(Versioned),R代表可重复迁移(Repeatable),U代表撤销迁移(Undo – 商业版)。 - 版本号:可用数字、点号分隔,如
1,1.1,2.0等。Flyway 按版本号的数值次序执行。 - 双下划线:版本号与描述之间必须使用两个下划线
__分隔。 - 描述:用下划线或空格分隔单词,清晰表达变更内容。
- 扩展名:
.sql,支持占位符替换等特性。
可重复迁移 R
以 R__描述.sql 命名的脚本会在每次内容(checksum)发生变化时重新执行,适合存储过程、视图等需要反复部署的对象。
第一个 Flyway 迁移演示
假设我们有一个 PostgreSQL 空数据库 mydb。
1. 创建迁移脚本
在 Flyway 的 sql 迁移目录(默认安装目录下的 sql 文件夹,或项目中的 db/migration)新建文件:
V1__Create_person_table.sql
CREATE TABLE person (
id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL
);
2. 执行迁移
命令行中执行:
flyway migrate
输出类似:
Database: jdbc:postgresql://localhost:5432/mydb (PostgreSQL 14)
Schema history table "public"."flyway_schema_history" does not exist yet
Successfully validated 1 migration (execution time 00:00.012s)
Creating Schema History table ...
Current version of schema "public": << Empty Schema >>
Migrating schema "public" to version "1 - Create person table"
Successfully applied 1 migration to schema "public" (execution time 00:00.033s)
3. 查看状态
执行 flyway info 可以查看所有迁移的状态:
+-----------+---------+---------------------+------+---------------------+---------+
| Category | Version | Description | Type | Installed On | State |
+-----------+---------+---------------------+------+---------------------+---------+
| Versioned | 1 | Create person table | SQL | 2025-03-20 14:25:00 | Success |
+-----------+---------+---------------------+------+---------------------+---------+
常用 Flyway 命令
| 命令 | 说明 |
|---|---|
migrate |
扫描迁移目录,执行所有未应用的版本迁移脚本 |
info |
打印所有迁移的详细信息与当前状态 |
validate |
校验已应用的迁移脚本是否被篡改,以及是否有未应用的迁移 |
baseline |
为已有数据库设置一个基准版本,让 Flyway 从该版本开始管理(忽略之前的脚本) |
repair |
修复元数据表,比如重新计算校验和、删除失败的迁移记录等 |
clean |
清理数据库中的所有对象(表格、视图等),慎用,通常只在开发环境使用 |
与 Spring Boot 深度集成
在实际的 Spring Boot 项目中,Flyway 几乎是无感的。
目录约定
将 SQL 脚本放在 src/main/resources/db/migration 下,Spring Boot 自动扫描并执行。支持多个位置的配置:
spring.flyway.locations: classpath:db/migration, classpath:db/specific-migration
执行时机
默认情况下,Flyway 在 Spring 应用上下文初始化数据源之后、JPA/Hibernate 等 ORM 生成 DDL 之前执行,确保数据库结构先存在。
自定义配置
spring:
flyway:
baseline-on-migrate: true # 当数据库非空时,自动进行基线操作
baseline-version: 0
placeholders:
app_name: MyApp # 在SQL中使用 ${app_name}
out-of-order: false # 是否允许执行顺序与版本号不一致的脚本
ignore-migration-patterns: "*:missing" # 忽略缺失的迁移(谨慎)
使用 Java 迁移
除了 SQL,Flyway 支持基于 Java 的迁移(适用于需要复杂逻辑的变更):
package db.migration;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
public class V2__Add_initial_data extends BaseJavaMigration {
public void migrate(Context context) throws Exception {
// 通过 context.getConnection() 执行自定义操作
}
}
该类也需要放在 db/migration 包下,命名规则同样遵循 V<version>__Description。
实践中的版本控制策略
- 版本号递增原则:已合并到主分支的脚本版本号只能新增,不能修改或删除。如需回滚,应编写新的迁移脚本。
- 开发分支的脚本命名:多人开发时,不同功能分支使用不同的版本号区间(如
V1000__,V2000__),合并前再统一重编号。 - 可重复迁移的使用:存储过程、触发器、视图等频繁变动的对象使用
R__前缀脚本,每次修改内容即可重新执行。 - 种子数据:测试数据可通过版本迁移脚本插入,也可放在可重复迁移中,但需注意幂等性。
Flyway 的校验与修复
当已执行的迁移脚本内容被修改时,再次运行 migrate 会校验失败:
Migration checksum mismatch for migration version 1
-> Applied to database : -1783829361
-> Resolved locally : 1890921433