数据库迁移工具入门:Flyway与Liquibase

说到数据库版本管理,市面上最主流的两个工具就是 Flyway 和 Liquibase。我这些年大大小小的项目都用过它们,说实话,各有各的脾气。今天咱们就好好聊聊这两个工具的核心概念,以及怎么选型。

你可能会问:为什么不用手动执行 SQL 脚本?嗯,我刚开始带团队时也这么干过。结果呢?有一次上线前,测试环境和生产环境的表结构差了三个字段,差点酿成事故。从那以后,我再也不敢轻视数据库版本管理了。

核心观点:数据库迁移工具的核心价值,就是把数据库 schema 的变化像代码一样纳入版本控制,让每一次变更都可追溯、可回滚、可复现。

Flyway 核心概念

Flyway 的理念很简单,就一句话:用版本号管理 SQL 脚本。它把每个数据库变更都看作一次"迁移",每个迁移文件都有一个唯一的版本号。

我个人习惯把 Flyway 比作"数据库的 Git"。你想想看,Git 用 commit id 管理代码版本,Flyway 用版本号管理数据库版本。道理是相通的。

Flyway 的迁移文件命名规则

Flyway 对文件命名有严格的要求。格式如下:

前缀 + 版本号 + 分隔符 + 描述 + 后缀

示例:
V1__create_user_table.sql
V2__add_email_column.sql
V3__create_order_table.sql

这里要注意几点:

  • 前缀:V 代表版本化迁移,U 代表撤销迁移,R 代表可重复迁移
  • 版本号:可以是数字,也可以用点号分隔,比如 V1.1__、V2.0.1__
  • 分隔符:固定两个下划线 __
  • 描述:简短说明,用下划线代替空格

我曾经踩过的坑:有一次我把版本号写成了 V1.0.0__init.sql,结果 Flyway 把 1.0.0 解析成了三个数字,导致后续 V1.0.1 的排序出了问题。后来我统一改用整数版本号,再也没出过这种问题。

Flyway 的工作流程

Flyway 会在数据库中创建一张元数据表(默认叫 flyway_schema_history),用来记录每次迁移的执行情况。每次启动时,它会做这几件事:

  1. 检查元数据表是否存在,不存在则创建
  2. 扫描文件系统中的迁移脚本
  3. 对比已执行的脚本和待执行的脚本
  4. 按版本号顺序执行未执行的脚本
  5. 记录执行结果到元数据表

说白了,Flyway 就是个"按顺序执行脚本"的工具。它不关心你脚本里写了什么,只关心版本号对不对、有没有重复执行。

Liquibase 核心概念

Liquibase 的思路和 Flyway 不太一样。它用 变更集(ChangeSet) 来描述数据库变更,每个变更集都有一个唯一的标识符。

我在项目中遇到过这样一个场景:需要同时支持 MySQL 和 PostgreSQL。用 Flyway 的话,得维护两套 SQL 脚本。但 Liquibase 的抽象能力就派上用场了——它可以用 XML、YAML、JSON 等格式描述变更,然后自动生成对应数据库的 SQL。

Liquibase 的变更集

一个典型的 Liquibase 变更集长这样:

<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

    <changeSet id="1" author="zhangsan">
        <createTable tableName="user">
            <column name="id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="name" type="varchar(100)">
                <constraints nullable="false"/>
            </column>
            <column name="email" type="varchar(200)"/>
        </createTable>
    </changeSet>

    <changeSet id="2" author="lisi">
        <addColumn tableName="user">
            <column name="phone" type="varchar(20)"/>
        </addColumn>
    </changeSet>
</databaseChangeLog>

每个 changeSet 由 id 和 author 共同唯一标识。Liquibase 会记录哪些变更集已经执行过,下次只执行新增的。

Liquibase 的追踪表

和 Flyway 类似,Liquibase 也会在数据库中创建两张元数据表:

  • DATABASECHANGELOG:记录已执行的变更集
  • DATABASECHANGELOGLOCK:用于分布式环境下的锁机制,防止并发执行

小技巧:Liquibase 支持 context 属性,可以按环境执行不同的变更集。比如开发环境执行测试数据插入,生产环境跳过。我在做 CI/CD 流水线时经常用这个功能。

工具选型对比

好了,两个工具的核心概念都讲完了。接下来咱们做个对比,帮你选型时有个参考。

对比维度 Flyway Liquibase
核心理念 版本号驱动的 SQL 脚本管理 变更集驱动的数据库抽象
脚本格式 纯 SQL XML/YAML/JSON + SQL
学习曲线 低,会 SQL 就能用 中,需要学习 DSL 语法
数据库兼容性 依赖 SQL 方言,切换数据库需改脚本 内置抽象层,切换数据库较方便
回滚支持 需手动编写撤销脚本(U 前缀) 内置回滚,可自动生成
分布式锁 不支持 支持,通过 DATABASECHANGELOGLOCK 表
社区生态 Spring Boot 原生集成,社区活跃 企业级功能丰富,文档完善

我个人的选型建议

说实话,没有银弹。选哪个取决于你的团队和项目情况:

  • 团队 SQL 功底扎实,项目只用一种数据库 → 选 Flyway。简单直接,上手快。
  • 需要支持多种数据库,或者有复杂的回滚需求 → 选 Liquibase。抽象层能省不少事。
  • Spring Boot 项目 → Flyway 集成更自然,几乎零配置。
  • 企业级项目,对变更审计、权限控制有要求 → Liquibase 的 Pro 版本提供了这些功能。

我的经验:小团队、快速迭代的项目,我倾向于 Flyway。大团队、多数据库、需要严格变更管控的项目,Liquibase 更合适。但不管选哪个,都比手动执行 SQL 强一百倍。

知识体系总览

下面这张图帮你梳理本章的核心知识点:

数据库迁移工具知识体系 数据库迁移工具 Flyway 版本号驱动 纯 SQL 脚本 flyway_schema_history V/U/R 前缀 Liquibase 变更集 ChangeSet XML/YAML/JSON DATABASECHANGELOG 数据库抽象层 选型建议:小团队快速迭代 → Flyway 大团队多数据库 → Liquibase

总结

Flyway 和 Liquibase 都是成熟的数据库迁移工具,没有的好坏。Flyway 胜在简单直接,适合 SQL 功底扎实的团队;Liquibase 胜在抽象能力强,适合多数据库场景。

我个人建议:先选一个用起来,比纠结选哪个更重要。等你用熟了,自然就知道什么时候该换、该换什么。毕竟,工具是为人服务的,不是反过来。