2. Liquibase 核心概念:ChangeLog、ChangeSet、DatabaseChangeLog 表、MD5Sum 校验机制

在深入回滚与并发迁移的 GC 停顿控制之前,必须牢固掌握 Liquibase 的四个核心概念。它们是整个迁移框架的基石,直接决定了变更的声明方式、执行顺序、状态追踪与完整性校验。本章将逐一拆解 ChangeLog、ChangeSet、DatabaseChangeLog 追踪表以及 MD5Sum 校验机制,并揭示它们如何协同工作。

2.1 ChangeLog:变更的编排清单

ChangeLog 是 Liquibase 迁移的入口文件,通常为 XML、YAML、JSON 或 SQL 格式。它定义了一组有序的数据库变更(ChangeSet),并控制这些变更的执行逻辑。

  • 根元素:<databaseChangeLog> 是所有 ChangeLog 文件的根节点。
  • 包含关系:支持通过 <include> 或 <includeAll> 引入子文件,实现模块化编排。
  • 上下文与标签:通过 context 和 labels 属性控制变更的生效环境(如 dev、prod)。
  • 逻辑控制:支持 preConditions、property 等高级编排能力。
最佳实践:将 ChangeLog 按业务模块拆分(如 changelogs/user/、changelogs/order/),避免单个文件过大导致解析时 GC 压力集中。

2.2 ChangeSet:原子变更单元

ChangeSet 是 ChangeLog 中的最小执行单元,代表一个不可分割的数据库变更。每个 ChangeSet 必须包含 id、author 和 filePath 三个属性,三者组合形成全局唯一标识。

属性 说明 示例
id 变更的唯一编号,建议使用语义化名称 create-user-table
author 变更作者标识 zhang-san
filePath ChangeSet 所在的 ChangeLog 路径 changelogs/v1.0.xml
runAlways 每次运行都执行(默认 false) false
runOnChange 当 ChangeSet 内容变化时重新执行 false
failOnError 执行失败时是否终止迁移 true
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog">
    <changeSet id="create-user-table" author="zhang-san">
        <createTable tableName="user">
            <column name="id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="username" type="varchar(50)">
                <constraints unique="true" nullable="false"/>
            </column>
            <column name="created_at" type="timestamp" defaultValueComputed="now()"/>
        </createTable>
    </changeSet>
</databaseChangeLog>

2.3 DatabaseChangeLog 表:状态追踪的基石

Liquibase 在目标数据库中维护两张核心追踪表:DATABASECHANGELOG 和 DATABASECHANGELOGLOCK。它们记录了所有已执行变更的元数据,是回滚与并发控制的基础。

DATABASECHANGELOG 表结构

字段名 类型 说明
ID VARCHAR(255) ChangeSet 的 id
AUTHOR VARCHAR(255) ChangeSet 的作者
FILENAME VARCHAR(255) ChangeSet 所在的文件路径
DATEEXECUTED TIMESTAMP 执行时间
ORDEREXECUTED INT 执行顺序号
MD5SUM VARCHAR(35) 变更内容的 MD5 校验值
DESCRIPTION VARCHAR(255) 变更操作的描述
COMMENTS VARCHAR(255) 用户自定义注释
TAG VARCHAR(255) 回滚标签
LIQUIBASE VARCHAR(20) 执行时的 Liquibase 版本
CONTEXTS VARCHAR(255) 生效的上下文
LABELS VARCHAR(255) 生效的标签
DEPLOYMENT_ID VARCHAR(10) 部署批次 ID

DATABASECHANGELOGLOCK 表:用于分布式环境下的并发锁控制,防止多个 Liquibase 实例同时修改数据库结构。

注意:在高并发迁移场景下,DATABASECHANGELOGLOCK 表的行锁竞争是 GC 停顿的潜在诱因之一。后续章节将专门分析锁等待与 GC 的关联。

2.4 MD5Sum 校验机制:变更完整性守护

MD5Sum 是 Liquibase 用于检测 ChangeSet 是否被篡改或意外修改的核心机制。每次执行 ChangeSet 时,Liquibase 会计算其内容的 MD5 哈希值,并存入 DATABASECHANGELOG.MD5SUM 字段。

校验流程

  1. 计算:对 ChangeSet 的 XML/YAML/JSON 内容(包括所有子元素和属性)计算 MD5 值。
  2. 比对:将计算值与数据库中已存储的 MD5SUM 进行比对。
  3. 决策:
    • 匹配 → 跳过该 ChangeSet(已执行且未变更)。
    • 不匹配 → 抛出 ValidationFailedException,阻止迁移继续。
    • 数据库无记录 → 执行该 ChangeSet。

MD5Sum 的生成规则

  • 仅对 ChangeSet 的 变更定义部分 计算,不包括 runAlways、runOnChange 等执行控制属性。
  • 对于 <sql> 或 <sqlFile> 类型的 ChangeSet,MD5 基于 SQL 文本内容计算。
  • 版本升级时,Liquibase 会自动处理 MD5 格式的兼容性(如从 3.x 到 4.x 的哈希算法调整)。
性能影响:MD5 计算本身开销极低(微秒级),但在大规模 ChangeLog 解析时,频繁的字符串拼接与哈希计算会触发短生命周期对象的创建,进而影响 Young GC 频率。这是后续 GC 调优章节的重点关注点。

2.5 核心概念关系图

下图展示了 ChangeLog、ChangeSet、DatabaseChangeLog 表与 MD5Sum 之间的协作关系:

Liquibase 核心概念协作关系 ChangeLog 变更编排清单 ChangeSet 原子变更单元 包含 MD5Sum 完整性校验 计算 DATABASECHANGELOG 表 ID | AUTHOR | FILENAME | MD5SUM | TAG | ... 执行后写入记录 存储校验值 回滚流程 基于 TAG 或 COUNT 回滚 读取 TAG 与执行顺序 DATABASECHANGELOGLOCK 表 分布式并发锁控制 回滚时需获取锁 GC 关注点 锁等待 + 对象创建

2.6 核心概念对比总结

概念 职责 存储位置 与 GC 的关联
ChangeLog 变更编排与模块化组织 文件系统 / 类路径 解析时产生大量临时字符串对象
ChangeSet 原子变更定义与执行 ChangeLog 文件内 MD5 计算时创建短生命周期对象
DATABASECHANGELOG 已执行变更的状态追踪 目标数据库 查询与写入产生 JDBC 往返开销
MD5Sum 变更完整性校验 DATABASECHANGELOG 表 哈希计算与字符串比对影响 CPU 与 GC
DATABASECHANGELOGLOCK 并发迁移的锁控制 目标数据库 锁等待导致线程阻塞,间接影响 GC 行为

2.7 常见误区与避坑指南

误区 1:修改已执行的 ChangeSet 内容
直接修改已提交的 ChangeSet 会导致 MD5Sum 不匹配,迁移失败。正确做法是新增一个 ChangeSet 来执行变更。
误区 2:忽略 DATABASECHANGELOGLOCK 表
在 CI/CD 流水线中,多个构建节点同时执行迁移时,必须确保锁机制正常工作,否则会出现数据竞争。
误区 3:ChangeLog 文件过大
单个 ChangeLog 包含数百个 ChangeSet 时,解析阶段的字符串处理会显著增加 Young GC 频率。建议按版本或模块拆分。