flyway 中 versioned 和 repeatable 迁移可混合使用,但需严格区分职责:versioned(如 v1.0__init.sql)一次性执行、版本递增、管理结构变更;repeatable(如 r__update_views.sql)每次校验哈希后重执行、管理视图/函数/动态数据;执行顺序为先 versioned(升序)、后 repeatable(字母序),禁止在 repeatable 中修改表结构或拆分同一功能。

Flyway 中的 repeatable 和 versioned 迁移可以混合使用,但需明确各自职责、执行顺序和约束条件,否则容易引发不可预期的行为(如重复执行、版本冲突、校验失败)。
两者的核心区别必须清楚
Versioned migration(带版本号,如 V1.0__init.sql):
- 一次性执行,成功后记录到 flyway_schema_history 表;
- 版本号严格递增,不可重复、不可跳过、不可降级;
- 用于定义数据库结构(建表、改列)、初始数据(INSERT 静态配置)等“只做一次”的变更。
Repeatable migration(无版本号,以 R__ 开头,如 R__update_views.sql):
- 每次 flyway migrate 都会执行(或重新执行),只要其内容哈希值变化;
- 不记录独立版本行,而是以 type = 'REPEATABLE' 形式在历史表中存一条记录,并持续更新 checksum;
- 适合管理视图、函数、存储过程、批量配置数据(如权限集、国家字典)等“可演进、需同步”的对象。
混合使用的合理场景与推荐模式
典型组合方式:
- Versioned 负责 DDL 基线:建库、建表、加索引、设约束;
-
Repeatable 负责逻辑封装与动态数据:视图定义、物化视图刷新逻辑、角色权限脚本、多环境通用配置表填充(如
config表中的开关项); -
避免用 Repeatable 替代 Versioned 的结构变更:比如不要用
R__add_column_user_email.sql去加字段——这绕过了版本控制,会导致协作混乱和回滚困难。
执行顺序与依赖规则
Flyway 总是按以下固定顺序执行迁移:
- 所有 versioned 迁移(按版本号升序);
- 所有 repeatable 迁移(按文件名字母序,
R__a.sql在R__b.sql前);
注意:
- Repeatable 迁移之间不能有显式依赖(Flyway 不支持
R__depends_on_R__.sql);若存在逻辑依赖(如先建视图 A,再建基于 A 的视图 B),应合并为一个R__views.sql文件; - Versioned 迁移可安全引用 repeatable 产出的对象(如 V2.0 中的存储过程调用 R__views 定义的视图),因为 versioned 总是先执行;
- Repeatable 迁移中不应修改已被 versioned 迁移创建的表结构(如
ALTER TABLE),否则 checksum 变化可能掩盖真实 DDL 演进路径,不利于审计和还原。
常见陷阱与规避建议
❌ 错误做法:
- 把同一个业务功能拆成 V__ 和 R__ 两部分(如 V3.0 建表 + R__insert_default_data),导致数据初始化不可重现或环境不一致;
- 在 repeatable 脚本中写
DROP TABLE IF EXISTS或CREATE OR REPLACE TABLE——这些语句在多数数据库不支持,且违背 schema 管理原则; - 反复修改 R__ 脚本并期望 Flyway 自动重放(它确实会),但未验证下游依赖(如应用层缓存、ETL 任务)是否兼容新逻辑;
- 启用
flyway.cleanOnValidationError=true后混用 repeatable,可能因 checksum 不匹配触发误清库。
✅ 推荐做法:
- 将 repeatable 脚本视为“声明式”而非“命令式”:只保证最终状态正确(如
CREATE OR REPLACE VIEW、TRUNCATE + INSERT配置表); - 对关键 repeatable 迁移加注释说明适用范围(如 “仅适用于 PostgreSQL 14+”,“需配合应用 v2.5+ 使用”);
- CI 流程中增加校验:比对本地
R__文件哈希与目标环境历史表中的checksum,提前发现未同步变更; - 必要时用
flyway repair修复 repeatable 的 checksum(仅当确认内容已正确部署且历史记录损坏时)。










