4. ChangeLog 文件结构:四种格式详解

ChangeLog 是 Liquibase 迁移的核心清单文件,它按顺序记录所有数据库变更。Liquibase 原生支持四种格式:XML、YAML、JSON 和 SQL。选择哪种格式取决于团队习惯、工具链集成度以及对可读性的要求。

核心原则:无论使用哪种格式,ChangeLog 的语义等价——即变更集(changeset)的 ID、作者、文件路径和变更顺序必须一致。格式只是序列化方式不同,Liquibase 引擎最终都会解析为统一的内存模型。

4.1 四种格式概览与对比

特性 XML YAML JSON SQL
官方推荐度 最高(原生格式) 高 中 中(面向 DBA)
可读性 结构化,标签冗余 简洁,缩进敏感 紧凑,括号多 纯 SQL 语句
IDE 支持 完善(XSD 校验) 良好 良好 标准 SQL 高亮
变更类型覆盖 全部 refactoring 标签 全部 全部 仅原生 SQL
版本控制友好度 高(标签 diff 清晰) 高(行级 diff) 中(行级 diff 但括号多) 高(纯文本)
适用场景 企业级、CI/CD 集成 DevOps 团队、配置即代码 API 驱动、动态生成 DBA 主导、遗留系统迁移

4.2 XML 格式 ChangeLog

XML 是 Liquibase 的原生格式,拥有最完整的 XSD 校验支持。所有 refactoring 标签(如 createTable、addColumn)都有明确的 XML 元素映射,IDE 自动补全和校验体验最佳。

<?xml version="1.0" encoding="UTF-8"?>
<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.23.xsd">

    <changeSet id="001" author="zhang.san">
        <createTable tableName="users">
            <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="email" type="varchar(255)"/>
        </createTable>
    </changeSet>

    <changeSet id="002" author="zhang.san">
        <addColumn tableName="users">
            <column name="status" type="varchar(20)" defaultValue="ACTIVE"/>
        </addColumn>
    </changeSet>
</databaseChangeLog>
XML 最佳实践:
  • 始终声明 databaseChangeLog 根元素并引用最新 XSD,确保 IDE 和 CI 工具能校验语法。
  • 每个 changeSet 必须包含 id 和 author 属性,这是数据库追踪的唯一键。
  • 使用 preConditions 标签保护敏感变更,避免重复执行导致错误。

4.3 YAML 格式 ChangeLog

YAML 格式以缩进层级代替 XML 的闭合标签,代码量减少约 30%-40%,在 DevOps 团队中非常流行。Liquibase 从 3.1 版本开始原生支持 YAML。

databaseChangeLog:
  - changeSet:
      id: 001
      author: li.si
      changes:
        - createTable:
            tableName: orders
            columns:
              - column:
                  name: id
                  type: bigint
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: user_id
                  type: bigint
                  constraints:
                    nullable: false
              - column:
                  name: total_amount
                  type: decimal(10,2)
  - changeSet:
      id: 002
      author: li.si
      changes:
        - addForeignKeyConstraint:
            baseTableName: orders
            baseColumnNames: user_id
            referencedTableName: users
            referencedColumnNames: id
            constraintName: fk_orders_users
YAML 避坑指南:
  • 缩进必须使用空格,禁止使用 Tab。建议统一为 2 个空格缩进。
  • 列表项前的 - 后面必须跟一个空格,否则解析失败。
  • 字符串值如果包含特殊字符(如 :、#),建议用双引号包裹。

4.4 JSON 格式 ChangeLog

JSON 格式适合程序化生成 ChangeLog 的场景,例如从数据库逆向工程工具导出、或由 CI/CD 管道动态拼接变更集。Liquibase 从 3.5 版本开始支持 JSON。

{
  "databaseChangeLog": [
    {
      "changeSet": {
        "id": "001",
        "author": "wang.wu",
        "changes": [
          {
            "createTable": {
              "tableName": "products",
              "columns": [
                {
                  "column": {
                    "name": "id",
                    "type": "bigint",
                    "autoIncrement": true,
                    "constraints": {
                      "primaryKey": true,
                      "nullable": false
                    }
                  }
                },
                {
                  "column": {
                    "name": "name",
                    "type": "varchar(200)",
                    "constraints": {
                      "nullable": false
                    }
                  }
                },
                {
                  "column": {
                    "name": "price",
                    "type": "decimal(10,2)"
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}
JSON 使用建议:JSON 格式不支持注释,因此建议在 ChangeLog 头部使用 context 或 labels 属性来标记变更集的用途。对于需要大量人工审阅的团队,优先选择 XML 或 YAML。

4.5 SQL 格式 ChangeLog

SQL 格式是最直接的方式——你直接编写原生 SQL 语句,Liquibase 负责追踪执行状态。这种方式对 DBA 最友好,但失去了跨数据库兼容性。

-- liquibase formatted sql
-- changeset zhao.liu:001
CREATE TABLE categories (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- changeset zhao.liu:002
ALTER TABLE categories ADD COLUMN parent_id BIGINT;
ALTER TABLE categories ADD CONSTRAINT fk_categories_parent
    FOREIGN KEY (parent_id) REFERENCES categories(id);

-- changeset zhao.liu:003
CREATE INDEX idx_categories_name ON categories(name);
SQL 格式关键规则:
  • 文件第一行必须是 -- liquibase formatted sql,否则 Liquibase 不会识别。
  • 每个变更集以 -- changeset author:id 注释行开始,后面紧跟 SQL 语句。
  • SQL 语句之间用空行分隔,Liquibase 默认以分号 ; 作为语句结束符。
  • 可以使用 -- rollback 注释块定义回滚 SQL,增强迁移安全性。

4.6 四种格式的解析流程对比

ChangeLog 四种格式解析流程 XML ChangeLog YAML ChangeLog JSON ChangeLog SQL ChangeLog XML 解析器 YAML 解析器 JSON 解析器 SQL 解析器 Liquibase 统一变更模型 数据库执行引擎

4.7 格式选择决策树

在实际项目中,选择哪种 ChangeLog 格式通常遵循以下决策逻辑:

  1. 团队构成:如果团队以 DBA 为主,优先选择 SQL 格式;如果以应用开发为主,优先选择 XML 或 YAML。
  2. 工具链集成:如果使用 Spring Boot + Liquibase 自动配置,XML 开箱即用;如果使用 Gradle/Maven 插件,YAML 更简洁。
  3. 跨数据库需求:如果需要支持多种数据库(如开发用 H2、生产用 PostgreSQL),必须使用 XML/YAML/JSON 格式,避免 SQL 格式的方言差异。
  4. 自动化程度:如果 ChangeLog 由代码生成器或 CI 管道动态生成,JSON 格式最易拼接。
重要提醒:不要在同一个 ChangeLog 文件中混用多种格式。Liquibase 允许通过 include 或 includeAll 引用不同格式的子文件,但单个文件必须保持格式统一。混合格式会导致解析器切换错误,引发不可预期的失败。