2. 核心概念:ChangeLog、ChangeSet、ID、Author、File Encoding、Context、Label
在 Liquibase 的迁移体系中,ChangeLog 是数据库变更的“总谱”,而 ChangeSet 则是谱中的每一个“乐章”。理解这七个核心概念,是编写可维护、可追溯、可协作的数据库版本脚本的基础。
2.1 ChangeLog:变更日志文件
ChangeLog 是 Liquibase 迁移的入口文件,通常以 XML、YAML、JSON 或 SQL 格式编写。它定义了数据库变更的顺序、依赖关系以及执行策略。
- 根元素:XML 格式下为
<databaseChangeLog>,YAML 格式下为databaseChangeLog:。 - 包含关系:一个 ChangeLog 可以引用其他 ChangeLog 文件(通过
<include>或<includeAll>),实现模块化管理。 - 属性声明:可在 ChangeLog 级别声明
logicalFilePath、objectQuotingStrategy等全局属性。
最佳实践:将 ChangeLog 按业务模块或版本号拆分,避免单个文件过大。例如:
v1.0.0/changelog-master.xml、v1.1.0/changelog-feature-orders.xml。
2.2 ChangeSet:变更集
ChangeSet 是 ChangeLog 中的最小执行单元,代表一次原子性的数据库变更。每个 ChangeSet 必须包含 ID 和 Author 两个唯一标识属性。
<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-4.20.xsd">
<changeSet id="1" author="zhang.san">
<createTable tableName="users">
<column name="id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="username" type="varchar(50)">
<constraints unique="true" nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
2.3 ID 与 Author:唯一标识
ID 和 Author 的组合构成了 ChangeSet 在数据库中的唯一键。Liquibase 通过 DATABASECHANGELOG 表记录已执行的 ChangeSet,确保每个变更只执行一次。
| 属性 | 说明 | 示例 |
|---|---|---|
| ID | ChangeSet 的序号或标识符,在同一 ChangeLog 中建议保持唯一 | 1、V1.0.0-001、add-users-table |
| Author | 变更的作者,通常使用系统用户名或团队约定名称 | zhang.san、devops-team、li.si |
| 组合唯一性 | ID + Author + filePath 共同决定 ChangeSet 是否已执行 | 1::zhang.san::changelogs/db.changelog-master.xml |
注意:一旦 ChangeSet 被标记为已执行(
already executed),严禁修改其 ID 或 Author,否则 Liquibase 会将其视为新的 ChangeSet 并尝试再次执行,导致重复变更或冲突。
2.4 File Encoding:文件编码
ChangeLog 文件的编码方式直接影响 SQL 语句中特殊字符(如中文、表情符号、欧元符号)的解析。Liquibase 默认使用 UTF-8 编码读取文件。
- 声明方式:在 ChangeLog 根元素中通过
encoding属性指定。 - 推荐值:始终使用
UTF-8,确保跨平台、跨团队的一致性。 - 常见问题:若文件实际编码与声明不一致,Liquibase 会抛出
UnsupportedEncodingException或产生乱码数据。
<databaseChangeLog encoding="UTF-8" ...>
<changeSet id="2" author="li.si">
<sql>
INSERT INTO users (username) VALUES ('张三');
</sql>
</changeSet>
</databaseChangeLog>
2.5 Context:上下文
Context 允许你为 ChangeSet 打上“环境标签”,控制其在特定场景下是否执行。常用于区分开发、测试、生产环境的差异化变更。
- 定义方式:在 ChangeSet 上添加
context属性,多个值用逗号分隔。 - 激活方式:运行 Liquibase 时通过
--contexts参数指定激活的上下文。 - 匹配逻辑:ChangeSet 的 context 值只要与激活列表中的任意一个匹配,即会执行。
<changeSet id="3" author="wang.wu" context="dev,test">
<insert tableName="config">
<column name="key" value="debug_mode"/>
<column name="value" value="true"/>
</insert>
</changeSet>
<changeSet id="4" author="wang.wu" context="prod">
<insert tableName="config">
<column name="key" value="debug_mode"/>
<column name="value" value="false"/>
</insert>
</changeSet>
2.6 Label:标签
Label 是另一种过滤机制,与 Context 类似但更灵活。Label 支持 逻辑表达式(AND、OR、NOT),适合复杂的执行条件判断。
| 特性 | Context | Label |
|---|---|---|
| 语法 | 逗号分隔的字符串列表 | 支持逻辑表达式(!、&、|) |
| 匹配方式 | 任意一个匹配即执行 | 表达式整体求值 |
| 典型场景 | 环境区分(dev/test/prod) | 功能开关、灰度发布、A/B 测试 |
| 示例 | context="dev,staging" |
labels="feature_x & !prod" |
<changeSet id="5" author="zhao.liu" labels="migration_v2 & (us_east | eu_west)">
<addColumn tableName="orders">
<column name="region" type="varchar(10)"/>
</addColumn>
</changeSet>
实战建议:使用 Context 做环境隔离,使用 Label 做功能维度隔离。两者可以同时使用,Liquibase 会先过滤 Context,再过滤 Label。
2.7 核心概念关系图
下图展示了 ChangeLog、ChangeSet 及其核心属性之间的层级关系与执行过滤流程:
2.8 核心概念速查表
| 概念 | 作用层级 | 是否必需 | 典型值/示例 |
|---|---|---|---|
| ChangeLog | 文件级 | 是 | db.changelog-master.xml |
| ChangeSet | 变更单元级 | 是 | 包含 <createTable>、<addColumn> 等 |
| ID | ChangeSet 属性 | 是 | 1、V2.0-add-index |
| Author | ChangeSet 属性 | 是 | zhang.san、devops-bot |
| File Encoding | ChangeLog 属性 | 推荐 | UTF-8 |
| Context | ChangeSet 属性 | 否 | dev、test,staging |
| Label | ChangeSet 属性 | 否 | feature_x & !prod |
记忆口诀:“ChangeLog 是总谱,ChangeSet 是乐句;ID+Author 定身份,Encoding 保不乱码;Context 分环境,Label 做开关。”