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等高级编排能力。
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 字段。
校验流程
- 计算:对 ChangeSet 的 XML/YAML/JSON 内容(包括所有子元素和属性)计算 MD5 值。
- 比对:将计算值与数据库中已存储的 MD5SUM 进行比对。
- 决策:
- 匹配 → 跳过该 ChangeSet(已执行且未变更)。
- 不匹配 → 抛出
ValidationFailedException,阻止迁移继续。 - 数据库无记录 → 执行该 ChangeSet。
MD5Sum 的生成规则
- 仅对 ChangeSet 的 变更定义部分 计算,不包括
runAlways、runOnChange等执行控制属性。 - 对于
<sql>或<sqlFile>类型的 ChangeSet,MD5 基于 SQL 文本内容计算。 - 版本升级时,Liquibase 会自动处理 MD5 格式的兼容性(如从 3.x 到 4.x 的哈希算法调整)。
2.5 核心概念关系图
下图展示了 ChangeLog、ChangeSet、DatabaseChangeLog 表与 MD5Sum 之间的协作关系:
2.6 核心概念对比总结
| 概念 | 职责 | 存储位置 | 与 GC 的关联 |
|---|---|---|---|
| ChangeLog | 变更编排与模块化组织 | 文件系统 / 类路径 | 解析时产生大量临时字符串对象 |
| ChangeSet | 原子变更定义与执行 | ChangeLog 文件内 | MD5 计算时创建短生命周期对象 |
| DATABASECHANGELOG | 已执行变更的状态追踪 | 目标数据库 | 查询与写入产生 JDBC 往返开销 |
| MD5Sum | 变更完整性校验 | DATABASECHANGELOG 表 | 哈希计算与字符串比对影响 CPU 与 GC |
| DATABASECHANGELOGLOCK | 并发迁移的锁控制 | 目标数据库 | 锁等待导致线程阻塞,间接影响 GC 行为 |
2.7 常见误区与避坑指南
直接修改已提交的 ChangeSet 会导致 MD5Sum 不匹配,迁移失败。正确做法是新增一个 ChangeSet 来执行变更。
在 CI/CD 流水线中,多个构建节点同时执行迁移时,必须确保锁机制正常工作,否则会出现数据竞争。
单个 ChangeLog 包含数百个 ChangeSet 时,解析阶段的字符串处理会显著增加 Young GC 频率。建议按版本或模块拆分。