1. 概述

上篇文章中,我们介绍了 Liquibase 作为数据库架构和数据管理工具的使用方法。

本文将深入探讨 Liquibase 的回滚功能——如何撤销已执行的数据库变更操作。⚠️ 这在生产级系统中是至关重要的能力。

2. Liquibase 迁移的分类

Liquibase 操作分为两类,对应不同的回滚语句生成方式:

  • 自动回滚:迁移操作能明确生成回滚步骤
  • 手动回滚:需要手动编写回滚命令,因为迁移指令无法自动确定回滚语句

例如: ✅ 创建表操作的回滚是删除该表,这可以明确推导,因此能自动生成回滚语句
删除表操作的回滚无法自动生成,因为无法确定表被删除前的状态,必须手动提供回滚指令

3. 编写简单回滚语句

下面是一个创建表的变更集示例,包含自定义回滚语句:

<changeSet id="testRollback" author="baeldung">
    <createTable tableName="baeldung_tutorial">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
        <column name="author" type="varchar(36)"/>
    </createTable>
    <rollback>
        <dropTable tableName="baeldung_tutorial"/>
    </rollback>
</changeSet>

踩坑提示:虽然 Liquibase 会为 createTable 自动生成回滚语句,但这里我们手动覆盖了默认行为。

执行迁移命令:

mvn liquibase:update

执行回滚命令:

mvn liquibase:rollback

⚠️ 直接执行回滚会失败!必须指定以下三种限制条件之一:

  • rollbackTag - 回滚到指定标签
  • rollbackCount - 回滚指定数量的变更集
  • rollbackDate - 回滚到指定时间点

3.1. 回滚到标签

为数据库状态打标签后,可回滚到该标签状态:

mvn liquibase:rollback -Dliquibase.rollbackTag=1.0

这将回滚标签 "1.0" 之后执行的所有变更集。

3.2. 按数量回滚

指定要回滚的变更集数量(例如回滚最近1个变更集):

mvn liquibase:rollback -Dliquibase.rollbackCount=1

3.3. 按日期回滚

回滚指定日期之后的所有变更:

mvn liquibase:rollback "-Dliquibase.rollbackDate=Jun 03, 2017"

日期格式需符合 ISO 标准或运行平台 DateFormat.getDateInstance() 的格式。

4. 变更集回滚选项

4.1. 多语句回滚

单个 <rollback> 标签可包含多个操作:

<changeSet id="multiStatementRollback" author="baeldung">
    <createTable tableName="baeldung_tutorial2">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <createTable tableName="baeldung_tutorial3">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <rollback>
        <dropTable tableName="baeldung_tutorial2"/>
        <dropTable tableName="baeldung_tutorial3"/>
    </rollback>
</changeSet>

4.2. 多回滚标签

变更集中可使用多个 <rollback> 标签,按出现顺序执行:

<changeSet id="multipleRollbackTags" author="baeldung">
    <createTable tableName="baeldung_tutorial4">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <createTable tableName="baeldung_tutorial5">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <rollback>
        <dropTable tableName="baeldung_tutorial4"/>
    </rollback>
    <rollback>
        <dropTable tableName="baeldung_tutorial5"/>
    </rollback>
</changeSet>

4.3. 引用其他变更集回滚

通过 changeSetIdchangeSetAuthor 引用其他变更集的回滚逻辑,避免代码重复:

<changeSet id="referChangeSetForRollback" author="baeldung">
    <dropTable tableName="baeldung_tutorial2"/>
    <dropTable tableName="baeldung_tutorial3"/>
    <rollback changeSetId="multiStatementRollback" changeSetAuthor="baeldung"/>
</changeSet>

4.4. 空回滚标签

使用空 <rollback/> 禁用自动回滚生成:

<changeSet id="emptyRollback" author="baeldung">
    <createTable tableName="baeldung_tutorial">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
        <column name="author" type="varchar(36)"/>
    </createTable>
    <rollback/>
</changeSet>

5. 回滚命令选项

5.1. 生成回滚脚本

生成回滚 SQL 而非直接执行:

  • rollbackSQL <tag> - 回滚到指定标签的 SQL 脚本
  • rollbackToDateSQL <date/time> - 回滚到指定时间的 SQL 脚本
  • rollbackCountSQL <value> - 回滚指定步数的 SQL 脚本

示例:

mvn liquibase:rollbackCountSQL 2

5.2. 生成未来回滚脚本

生成将当前数据库回滚到未来状态的 SQL 脚本(适用于部署前的回滚预案):

mvn liquibase:futureRollbackSQL

5.3. 测试更新与回滚

执行完整迁移后立即回滚,用于验证变更集的正确性(不改变最终数据库状态):

mvn liquibase:updateTestingRollback

简单粗暴的测试方式:实际执行变更再回滚,确保操作可逆。

6. 总结

本文系统介绍了 Liquibase 回滚功能的核心概念和实用技巧,包括:

  • 自动/手动回滚的适用场景
  • 三种回滚限制方式(标签/数量/日期)
  • 变更集中回滚语句的灵活配置
  • 回滚脚本的生成与测试方法

完整代码示例可在 GitHub 获取。


原始标题:Introduction to Liquibase Rollback | Baeldung