数据库版本控制:Flyway 入门指南
数据库 DevOps Flyway
Flyway 实战指南:中小企业如何用好数据库版本控制
一句话总结:Flyway 让数据库变更像代码一样可追踪、可协作、可回滚(逻辑上)。
在中小团队中,数据库变更常常是“人肉操作”:开发在本地改表,测试手动同步,上线前 DBA 手写 SQL。结果?环境不一致、上线失败、数据错乱……
Flyway 就是为解决这些问题而生的。
本文不讲理论,只聚焦 真实场景 + 推荐做法,帮你快速落地,并重点澄清两个关键限制:
✅ 文件命名规范
✅ 同一个版本号只能有一个迁移文件
一、为什么用 Flyway?——解决什么痛点?
❌ 传统方式的问题
- 开发改了表结构,测试环境没同步 → 测试失败
- 上线时漏执行 SQL → 应用报错
- 多人协作改数据库 → 脚本冲突、覆盖
- 想知道“当前数据库版本”?只能靠猜
✅ Flyway 带来的价值
- 版本化:每个 SQL 脚本都有唯一版本号(如
V1__xxx.sql) - 自动化:应用启动自动执行未运行的迁移
- 一致性:所有环境(dev/test/prod)结构一致
- 可审计:
flyway_schema_history表记录所有变更
二、Flyway 文件命名规范(必须遵守!)
Flyway 严格依赖文件名来识别脚本类型和执行顺序。命名错误会导致脚本被忽略或报错。
✅ 正确格式
| 类型 | 命名格式 | 示例 | 说明 |
|---|---|---|---|
| 版本化迁移 | V<版本号>__<描述>.sql | V1__Create_users.sql | 必须唯一版本号,按顺序执行 |
| 可重复迁移 | R__<描述>.sql | R__Create_user_view.sql | checksum 变更时重跑(用于视图、函数) |
🔑 关键细节
V和R必须大写- 版本号后是 两个下划线
__(不是_!) - 描述中不能包含空格或特殊字符(建议用下划线或驼峰)
- 文件扩展名必须是
.sql - 可重复迁移的脚本,一定要保证脚本幂等性,例如
create table if not exists避免报错,或者唯一索引的变种通过insert ignore避免重复插入
❌ 常见错误
v1__create.sql → 小写 v,不识别
V1_create.sql → 只有一个下划线,不识别
V1.1__create.sql → 版本号含点,虽合法但不推荐(用 V1_1 更稳妥)
V1__Create Table.sql → 描述含空格,可能出问题
三、核心限制:同一个版本号只能有一个文件!
这是 Flyway 最常被忽视但最关键的规则。
❌ 错误示例
db/migration/
├── V1__Create_table.sql
└── V1__Insert_test_data.sql ← ⚠️ Flyway 启动时报错!
错误信息:
Found more than one migration with version 1
✅ 为什么这样设计?
- Flyway 用版本号作为主键记录在
flyway_schema_history表中 - 每个版本号对应一次原子变更,不能拆成多个文件
✅ 正确做法
- 合并逻辑:把建表和初始数据写在一个
V1__Init.sql中(如果都适用于所有环境) - 或按顺序编号:
V1__Create_users_table.sql V2__Insert_test_users.sql -- 即使是测试数据,也用 V2
💡 记住:版本号是全局唯一的“变更 ID”,不是“功能分组”。
四、怎么集成 Flyway?——Spring Boot 5 分钟上手
Step 1:添加依赖(Maven)
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
Step 2:准备符合规范的脚本
-- ✅ 正确命名:V1__Create_users.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
Step 3:启动应用,自动迁移!
./mvnw spring-boot:run
Flyway 自动执行 V1__Create_users.sql,并在数据库创建 flyway_schema_history 表。
五、如何配置多环境?——解决“测试数据只在 dev 执行”
场景需求
- 所有环境:都要建
users表(V1) - 仅 dev:插入测试用户
- 仅 prod:插入管理员
✅ 推荐做法:目录隔离 + 唯一版本号
1. 目录结构
src/main/resources/db/migration/
├── common/
│ └── V1__Create_users.sql
├── dev/
│ └── V2__Insert_test_users.sql ← 版本号 V2
└── prod/
└── V2__Insert_admin_user.sql ← 版本号也是 V2,但不会同时加载
⚠️ 注意:
dev/V2__...和prod/V2__...不会同时出现在一个环境的迁移路径中,所以不违反“版本唯一”规则。
2. 配置文件
application-dev.yml
spring:
flyway:
locations: classpath:db/migration/common,classpath:db/migration/dev
application-prod.yml
spring:
flyway:
locations: classpath:db/migration/common,classpath:db/migration/prod
3. 启动命令
# 开发环境:执行 V1 + V2(dev)
./mvnw spring-boot:run --spring.profiles.active=dev
# 生产环境:执行 V1 + V2(prod)
java -jar app.jar --spring.profiles.active=prod
绝对禁止:在同一个 locations 路径下放两个 V2 脚本!
Flyway 会在启动时直接报错退出。
六、避坑指南:中小企业最常踩的 3 个坑
坑 1:试图用多个文件共享一个版本号
- 错误:
V1__a.sql+V1__b.sql - 正确:合并为
V1__Init.sql,或拆成V1+V2
坑 2:命名不规范导致脚本被忽略
- 错误:
v1_create.sql(小写 v) - 正确:
V1__Create.sql(大写 V + 双下划线)
坑 3:在 prod 环境误执行 dev 脚本
- 错误:所有脚本放同一目录
- 正确:用
locations严格隔离环境
七、最佳实践总结
| 规则 | 说明 |
|---|---|
| 命名规范 | V<版本号>__<描述>.sql,大写 V,双下划线 |
| 版本唯一 | 同一迁移路径下,每个版本号只能有一个文件 |
| 环境隔离 | 用 common/dev/prod 目录 + Spring Profile 控制加载 |
| 版本递增 | 即使是环境特有脚本,也按 V1 → V2 → V3 顺序编号 |
| 禁止修改 | 已执行的脚本内容不可更改,修正请用新版本 |
结语
Flyway 的威力不在于复杂功能,而在于用简单规则解决协作难题。
只要牢记两点:
- 命名要规范(
V1__xxx.sql) - 版本号不能重复(一个 V1,一个文件)
再配合多环境目录隔离,你就能在中小企业中安全、高效地管理数据库变更。
📚 官方参考:Flyway Migration Naming
💡 小技巧:执行flyway info查看当前数据库已应用的版本,快速定位问题。