1. 简介

本文将介绍几种使用 Flyway 回滚数据库迁移的方案。对于线上变更频繁的系统来说,可逆的数据库变更是一项刚需,而 Flyway 本身并不原生支持回滚(Community 版本),但我们可以通过一些方式“模拟”或“真正”实现回滚。

⚠️ 注意:本文演示使用的是命令行版本的 Flyway,但核心逻辑同样适用于 Java API、Maven 插件等集成方式。


2. 通过标准迁移模拟回滚

最简单粗暴的方式,就是写一个“反向 SQL”作为新的迁移脚本。虽然 Flyway 不支持自动回滚,但我们可以手动补一个“撤回”脚本。

2.1 创建初始迁移

我们先创建一个 book 表作为初始结构。新建迁移文件:

-- V1_0__create_book_table.sql
create table book (
  id numeric,
  title varchar(128),
  author varchar(256),
  constraint pk_book primary key (id)
);

执行迁移:

./flyway migrate

✅ 此时 book 表已创建,Flyway 的 flyway_schema_history 表中记录了该版本。

2.2 模拟回滚操作

假设我们发现这个表建错了,需要“回滚”。由于 Flyway Community 不支持 undo,我们只能再写一个反向操作:

-- V2_0__drop_table_book.sql
drop table book;

再次执行迁移:

./flyway migrate

查看迁移历史:

./flyway info

输出结果:

+-----------+---------+-------------------+------+---------------------+---------+
| Category  | Version | Description       | Type | Installed On        | State   |
+-----------+---------+-------------------+------+---------------------+---------+
| Versioned | 1.0     | create book table | SQL  | 2020-08-29 16:07:43 | Success |
| Versioned | 2.0     | drop table book   | SQL  | 2020-08-29 16:08:15 | Success |
+-----------+---------+-------------------+------+---------------------+---------+

🔍 重点观察:

  • 两条记录都是 Versioned 类型,状态均为 Success
  • 没有体现“回滚”关系,审计日志中看不出 V2.0 是为了撤销 V1.0
  • 从数据库角度看,表被删了,效果达到了,但缺乏可追溯性

✅ 优点:简单直接,兼容所有 Flyway 版本
❌ 缺点:破坏了版本递增语义,审计困难,容易踩坑(比如重复执行)


3. 使用 Flyway Undo(商业版功能)

如果你使用的是 Flyway Pro 或 Enterprise 版本,可以使用官方提供的 undo 命令。这才是真正的、结构化的回滚机制。

⚠️ 重要提醒:Flyway Undo 是商业功能,Community Edition 不可用

3.1 创建迁移与反向迁移文件

我们需要为每个正向迁移配一个对应的“反向迁移”文件。

-- V1_0__create_book_table.sql
create table book (
  id numeric,
  title varchar(128),
  author varchar(256),
  constraint pk_book primary key (id)
);

对应反向操作:

-- U1_0__create_book_table.sql
drop table book;

📌 命名规范:

  • 正向迁移前缀为 V
  • 反向迁移前缀为 U
  • 版本号和描述需完全一致,Flyway 才能自动匹配

3.2 执行迁移并验证状态

先查看当前迁移状态:

./flyway -pro info

输出:

+-----------+---------+-------------------+------+--------------+---------+----------+
| Category  | Version | Description       | Type | Installed On | State   | Undoable |
+-----------+---------+-------------------+------+--------------+---------+----------+
| Versioned | 1.0     | create book table | SQL  |              | Pending | Yes      |
+-----------+---------+-------------------+------+--------------+---------+----------+

✅ 注意 Undoable: Yes 字段,说明 Flyway 检测到了对应的 U 文件。

执行迁移:

./flyway migrate

迁移完成后,数据库中会出现 book 表:

                List of relations
 Schema |         Name          | Type  |  Owner   
--------+-----------------------+-------+----------
 public | book                  | table | flyway_user
 public | flyway_schema_history | table | flyway_user
(2 rows)

3.3 执行回滚操作

现在我们可以使用 undo 命令安全回滚:

./flyway -pro undo

回滚成功后,再次查看状态:

./flyway -pro info

输出:

+-----------+---------+-------------------+----------+---------------------+---------+----------+
| Category  | Version | Description       | Type     | Installed On        | State   | Undoable |
+-----------+---------+-------------------+----------+---------------------+---------+----------+
| Versioned | 1.0     | create book table | SQL      | 2020-08-22 15:48:00 | Undone  |          |
| Undo      | 1.0     | create book table | UNDO_SQL | 2020-08-22 15:49:47 | Success |          |
| Versioned | 1.0     | create book table | SQL      |                     | Pending | Yes      |
+-----------+---------+-------------------+----------+---------------------+---------+----------+

🔍 关键变化:

  • 多出一条 Category: Undo 的记录
  • Versioned 记录状态变为 Undone
  • 审计日志清晰体现“谁被回滚了”,可追溯性强 ✅

⚠️ 注意限制:

  • undo 要求原始迁移必须完整成功执行,中途失败的迁移无法回滚
  • 不支持对 repeatable 迁移进行 undo
  • 需要额外维护 U 脚本,增加维护成本

4. 总结

方式 是否需要商业版 审计可追溯 使用难度 推荐场景
✅ 模拟回滚(V2.0) ❌ 弱 简单 小项目、临时修复
✅ Flyway Undo ✅ 强 中等 生产环境、需审计

📌 核心建议:

  • 如果你在生产环境使用 Flyway,且对变更审计有要求,强烈建议升级到 Pro 或 Enterprise 版本,使用 undo 功能。
  • 若只能用 Community 版,务必规范命名反向迁移脚本(如 V2_1__undo_create_book_table.sql),并通过文档或注释标明其用途,避免后续维护踩坑。

🔄 数据库迁移的本质是“版本控制”,而回滚能力是版本控制的基石。选择合适的方式,才能让 DB 变更像代码一样安全可控。


原始标题:Rolling Back Migrations with Flyway | Baeldung