4. 依赖关系声明方式:在 XML 中声明 dependsOn、在 YAML 中声明、在 JSON 中声明、在 SQL 中声明
Liquibase 支持四种变更集描述格式:XML、YAML、JSON 和 SQL。每种格式都提供了声明依赖关系(dependsOn)的语法。理解这些声明方式,是进行冒烟验证和故障排查的基础——错误的格式或遗漏的依赖声明,是导致变更集执行顺序混乱的常见根源。
核心原则:无论使用哪种格式,
dependsOn 都指向一个或多个已存在的 changeset,通过其 id、author 和 filePath(可选)进行唯一标识。冒烟验证的第一步,就是确认这些引用在目标数据库中真实存在。
4.1 在 XML 中声明 dependsOn
XML 是 Liquibase 最传统、最成熟的格式。依赖关系通过 <preConditions> 内部的 <changesetExecuted> 元素,或直接在 <changeset> 上使用 dependsOn 属性来声明。推荐使用 dependsOn 属性,因为它更直观、更简洁。
<?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.20.xsd">
<changeSet id="1" author="alice">
<createTable tableName="users">
<column name="id" type="int">
<constraints primaryKey="true"/>
</column>
<column name="name" type="varchar(255)"/>
</createTable>
</changeSet>
<changeSet id="2" author="bob" dependsOn="1">
<comment>依赖 changeset id=1, author=alice</comment>
<addColumn tableName="users">
<column name="email" type="varchar(255)"/>
</addColumn>
</changeSet>
<!-- 多依赖:使用逗号分隔 -->
<changeSet id="3" author="carol" dependsOn="1, 2">
<createIndex indexName="idx_users_email" tableName="users">
<column name="email"/>
</createIndex>
</changeSet>
</databaseChangeLog>
XML 声明要点:
dependsOn属性值是一个或多个changeset的id(字符串),多个 id 用逗号分隔。- 默认情况下,Liquibase 会在同一个
databaseChangeLog文件中查找同author的变更集。如果依赖跨文件或跨 author,需要使用changesetExecuted前置条件。 - 故障排查时,检查
dependsOn引用的id是否与目标变更集的id完全匹配(包括大小写和空格)。
4.2 在 YAML 中声明 dependsOn
YAML 格式以其简洁和可读性受到许多团队的青睐。依赖关系通过 dependsOn 键来声明,其值可以是一个字符串(单个依赖)或一个列表(多个依赖)。
databaseChangeLog:
- changeSet:
id: 1
author: alice
changes:
- createTable:
tableName: orders
columns:
- column:
name: id
type: int
constraints:
primaryKey: true
- column:
name: product
type: varchar(255)
- changeSet:
id: 2
author: bob
dependsOn: "1" # 单依赖,字符串形式
changes:
- addColumn:
tableName: orders
columns:
- column:
name: quantity
type: int
- changeSet:
id: 3
author: carol
dependsOn: # 多依赖,列表形式
- "1"
- "2"
changes:
- createIndex:
indexName: idx_orders_product
tableName: orders
columns:
- column:
name: product
YAML 声明要点:
- YAML 对缩进敏感,
dependsOn必须与id、author在同一缩进层级。 - 多依赖时,使用列表(以
-开头)比逗号分隔字符串更清晰,也更容易排查遗漏。 - 冒烟验证时,检查 YAML 解析是否报错——错误的缩进会导致
dependsOn被忽略,从而破坏依赖链。
4.3 在 JSON 中声明 dependsOn
JSON 格式在自动化生成和工具集成场景中很常见。依赖关系通过 "dependsOn" 键来声明,其值可以是字符串或数组。
{
"databaseChangeLog": [
{
"changeSet": {
"id": "1",
"author": "alice",
"changes": [
{
"createTable": {
"tableName": "products",
"columns": [
{ "column": { "name": "id", "type": "int", "constraints": { "primaryKey": true } } },
{ "column": { "name": "name", "type": "varchar(255)" } }
]
}
}
]
}
},
{
"changeSet": {
"id": "2",
"author": "bob",
"dependsOn": "1",
"changes": [
{
"addColumn": {
"tableName": "products",
"columns": [
{ "column": { "name": "price", "type": "decimal(10,2)" } }
]
}
}
]
}
},
{
"changeSet": {
"id": "3",
"author": "carol",
"dependsOn": ["1", "2"],
"changes": [
{
"createIndex": {
"indexName": "idx_products_name",
"tableName": "products",
"columns": [
{ "column": { "name": "name" } }
]
}
}
]
}
}
]
}
JSON 声明要点:
- JSON 要求严格的键名和字符串引号。
dependsOn必须使用双引号,且值如果是字符串也必须用双引号。 - 多依赖时,使用数组
["1", "2"]形式。注意数组元素是字符串,不是对象。 - 故障排查时,使用 JSON 验证工具检查文件格式。一个常见的错误是遗漏逗号或多余逗号,导致整个
databaseChangeLog解析失败,依赖关系自然无法生效。
4.4 在 SQL 中声明 dependsOn
SQL 格式与其他三种格式有本质区别:它没有结构化的 dependsOn 属性。依赖关系通过 SQL 注释中的 Liquibase 指令来声明,或者通过 preconditions 注释块来实现。
-- liquibase formatted sql
-- changeset alice:1
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(255)
);
-- rollback DROP TABLE customers;
-- changeset bob:2 dependsOn:1
-- 依赖 changeset alice:1
ALTER TABLE customers ADD COLUMN phone VARCHAR(20);
-- rollback ALTER TABLE customers DROP COLUMN phone;
-- changeset carol:3 dependsOn:1,2
-- 多依赖:依赖 alice:1 和 bob:2
CREATE INDEX idx_customers_name ON customers(name);
-- rollback DROP INDEX idx_customers_name;
SQL 声明要点:
dependsOn指令必须写在-- changeset注释行的末尾,格式为dependsOn:id或dependsOn:id1,id2。- SQL 格式中,
dependsOn只能引用同一个author的变更集。如果需要跨 author 依赖,必须使用-- preconditions注释块。 - 冒烟验证时,检查注释行是否被正确解析。注释中的拼写错误(如
dependsOn写成dependOn)会导致依赖被静默忽略。
4.5 四种声明方式对比
| 特性 | XML | YAML | JSON | SQL |
|---|---|---|---|---|
| 声明位置 | <changeSet> 属性 |
changeSet 键值对 |
"changeSet" 键值对 |
-- changeset 注释行 |
| 单依赖语法 | dependsOn="1" |
dependsOn: "1" |
"dependsOn": "1" |
dependsOn:1 |
| 多依赖语法 | dependsOn="1, 2" |
dependsOn: ["1", "2"] |
"dependsOn": ["1", "2"] |
dependsOn:1,2 |
| 跨 author 支持 | 需 changesetExecuted |
需 changesetExecuted |
需 changesetExecuted |
需 -- preconditions |
| 常见故障点 | 属性拼写、逗号空格 | 缩进错误、列表格式 | 引号遗漏、逗号错误 | 注释拼写、author 不匹配 |
4.6 依赖声明方式的结构对比
下面的 SVG 图展示了四种格式在声明依赖时的结构差异,帮助你在冒烟验证时快速定位声明位置。
4.7 故障排查:依赖声明常见错误
在冒烟验证阶段,以下错误是导致依赖关系失效的高频原因。建议在验证脚本中逐一检查。
| 错误类型 | XML 示例 | YAML 示例 | JSON 示例 | SQL 示例 |
|---|---|---|---|---|
| 拼写错误 | dependsOn="1" 写成 dependOn="1" |
dependsOn: 写成 dependOn: |
"dependsOn" 写成 "dependOn" |
dependsOn:1 写成 dependOn:1 |
| id 不匹配 | 引用的 id 包含空格或大小写不一致 | 引用的 id 与目标 id 类型不一致(如 "1" vs 1) | 引用的 id 与目标 id 字符串不精确匹配 | 引用的 id 与 changeset 注释中的 id 不一致 |
| author 缺失 | 跨 author 依赖时未使用 changesetExecuted |
跨 author 依赖时未使用 changesetExecuted |
跨 author 依赖时未使用 changesetExecuted |
SQL 格式默认只匹配同 author,跨 author 需 -- preconditions |
| 格式错误 | 多依赖逗号后有多余空格 | 列表缩进错误导致解析失败 | 数组元素未加引号 | 注释行被 SQL 解析器忽略 |
实战建议:在 CI/CD 流水线中,建议对每种格式的 changelog 文件执行
liquibase validate 命令。该命令会检查所有 dependsOn 引用的变更集是否在 changelog 中定义,并报告任何格式错误。这是冒烟验证中最直接、最有效的自动化手段。