flyway不支持任意回滚,仅能通过新增逆向脚本实现有限回退;liquibase需在changeset中显式定义rollback逻辑,支持多种声明方式但依赖人工编写;二者均要求数据库处于干净状态,回滚非万能,须结合蓝绿发布等更可靠方案。

Flyway 的版本号是严格递增的,不支持任意回滚
Flyway 把迁移看作单向演进过程,flyway migrate 执行后,schema_version 表里只记录已应用的版本和状态,没有“回退逻辑”的存储位置。它默认不提供 flyway undo 或类似命令——这不是遗漏,而是设计取舍。
常见错误现象:flyway repair 被误当成回滚用;或手动删 schema_version 行再重跑,结果触发校验失败(checksum mismatch)。
- 真正能用的“回退”只有:写一个新
V2__rollback_to_v1.sql迁移脚本,显式执行逆向操作(比如DROP COLUMN改成ADD COLUMN) - 如果用了
flyway clean,必须确保数据库可清空——生产环境禁用 - 社区版完全不支持
undo;Pro 版虽有flyway undo,但要求所有迁移脚本带undo配对,且只支持上一个版本(不能跳回 V1 → V3)
Liquibase 的 rollback 命令依赖 changelog 中的 rollback 属性
Liquibase 默认也不自动保存反向操作,它的 rollback 能力不是开箱即用的,而是靠你在每个 changeSet 里显式声明怎么撤回。
使用场景:你改了表结构、插了测试数据、甚至调了存储过程,都得自己写清楚“怎么撤销”。否则 liquibase rollbackCount 1 会直接报错:Cannot rollback changeset: no rollback statement provided。
- 支持三种回滚方式:内联
<rollback>SQL</rollback>、引用rollbackScript文件、或用内置标签如<dropcolumn></dropcolumn>(它自带逆操作) -
rollback不检查实际数据状态,只按 changelog 执行——如果中间有人手动改库,rollback 可能失败或产生脏数据 - XML/YAML/JSON 格式都支持 rollback 定义,但 SQL 格式(
.sqlchangelog)只能靠--rollback注释块,易被忽略或格式写错
两者对“重复执行”和“版本冲突”的处理逻辑完全不同
Flyway 靠文件名哈希值做校验,Liquibase 靠 id/author/filepath 三元组加 checksum。这导致它们在协作开发、分支合并、CI 重跑时出问题的方式不一样。
常见错误现象:开发 A 提交 V2__add_user_table.sql,开发 B 同时提交 V2__create_audit_log.sql —— Flyway 直接报错“duplicate version”,Liquibase 则可能让两个 V2 共存(只要 id 不同),但上线时顺序不确定,引发依赖错误。
- Flyway 要求版本号全局唯一且递增,适合强管控流程;Liquibase 允许并行开发,但需要团队约定
author和id规范 - Flyway 的
repair是为修复 checksum 不一致而设,不是为解决冲突;Liquibase 的changelogSync可把现有 DDL 记录为已执行,但不会生成 rollback - CI 环境中,Flyway 更怕“本地多跑一次”,Liquibase 更怕“changelog 文件被覆盖丢失 rollback 块”
回滚能力不等于线上故障恢复能力
不管是 flyway undo 还是 liquibase rollback,都假设数据库处于“干净迁移态”——没手工改过结构、没绕过工具插过数据、没跨版本跳迁。现实里这三个条件常不满足。
- 真正高可用场景下,回滚只是兜底选项;更可靠的是蓝绿发布、影子表切换、或应用层兼容旧结构
- Liquibase 的 rollback 脚本如果含
DELETE FROM,执行后无法还原数据;Flyway 的“重写 V2 为逆向 SQL”也一样不可逆 - 所有回滚操作都应先在预发环境完整验证,尤其注意外键约束、索引失效、序列值偏移等隐性影响










