1. Liquibase 概述

1.1 Liquibase 是什么

Liquibase 是一个开源、与数据库无关的数据库变更管理工具。它通过声明式变更集(ChangeSet)和版本化变更日志(ChangeLog),将数据库 Schema 的每一次修改记录为可追踪、可回滚、可协作的“代码资产”。

核心工作模式:开发者编写数据库变更描述(XML / YAML / JSON / SQL),Liquibase 自动将其转换为目标数据库的 DDL/DML,并维护一张 DATABASECHANGELOG 表来记录哪些变更已执行、哪些尚未执行。

一句话定义:Liquibase = 数据库 Schema 的 Git + Maven,让数据库变更像应用代码一样受版本控制。

1.2 核心价值

价值维度 说明 典型收益
版本可追溯 每次变更生成唯一 ID,记录执行时间、作者、MD5 校验和 快速定位“谁、在何时、改了哪个表”
环境一致性 开发、测试、预发、生产使用同一份 ChangeLog 消除“在我机器上能跑”的 Schema 差异
自动回滚 支持 rollbackCount、rollbackToDate、rollbackToTag 上线失败时秒级回退到安全版本
多数据库兼容 同一份 ChangeLog 可运行于 MySQL、PostgreSQL、Oracle、SQL Server 等 30+ 数据库 减少数据库迁移时的适配工作量
CI/CD 集成 提供 Maven、Gradle、Spring Boot、命令行、Jenkins 等多种集成方式 数据库变更纳入自动化流水线

1.3 与传统 SQL 迁移的对比

对比维度 传统 SQL 迁移(手动脚本) Liquibase 自动化迁移
变更记录 依赖文件夹命名或备注文档 自动写入 DATABASECHANGELOG 表
重复执行防护 需手动判断是否已执行(如 IF NOT EXISTS) 基于 ChangeSet ID + 文件路径 + MD5 自动跳过已执行项
回滚能力 需单独编写回滚脚本,容易遗漏 ChangeSet 内嵌 rollback 标签,自动生成回滚语句
数据库兼容 每套数据库维护独立脚本 ChangeLog 抽象为数据库无关格式,自动转换
协作冲突 多人修改同一表时容易覆盖 ChangeSet 按顺序执行,冲突在代码审查阶段暴露
CI/CD 集成 需自行编写 Shell 或 Python 调度 原生支持 Maven/Gradle/Spring Boot 插件
注意:传统 SQL 迁移在小型项目或一次性数据修复中仍有价值,但在多环境、多版本、多人协作的企业级项目中,Liquibase 的自动化能力可显著降低人为失误风险。

1.4 适用场景

  • 微服务架构:每个服务独立数据库,Liquibase 作为服务启动时的 Schema 初始化组件
  • 持续交付流水线:数据库变更与应用代码一同构建、测试、部署
  • 多环境管理:开发 → 测试 → 预发 → 生产,确保 Schema 版本一致
  • 数据库即代码(Database as Code):将 DDL 纳入 Git 仓库,支持 Code Review
  • 跨数据库迁移:从 MySQL 迁移到 PostgreSQL 或 Oracle 时,ChangeLog 可复用
  • 合规审计:DATABASECHANGELOG 表提供完整的变更审计轨迹

1.5 Liquibase 核心工作流程

Liquibase 核心工作流程 编写 ChangeLog XML / YAML / JSON / SQL 定义 ChangeSet id + author + changes 执行迁移 update / rollback / tag DATABASECHANGELOG 记录所有已执行 ChangeSet DATABASECHANGELOGLOCK 分布式锁防止并发执行 目标数据库 每次执行 update 时,Liquibase 先读取 ChangeLog,对比 DATABASECHANGELOG,仅执行未记录的 ChangeSet

1.6 典型 ChangeLog 示例

<?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="zhangsan">
        <createTable tableName="user">
            <column name="id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="username" type="varchar(50)">
                <constraints nullable="false" unique="true"/>
            </column>
            <column name="email" type="varchar(100)"/>
        </createTable>
        <rollback>
            DROP TABLE IF EXISTS user;
        </rollback>
    </changeSet>

    <changeSet id="2" author="lisi">
        <addColumn tableName="user">
            <column name="phone" type="varchar(20)"/>
        </addColumn>
    </changeSet>
</databaseChangeLog>
最佳实践:每个 ChangeSet 只包含一个逻辑变更(如创建一张表或添加一个字段),便于回滚和代码审查。ChangeSet 的 id 建议使用数字序列或 JIRA 工单号,避免使用时间戳(多人协作时容易冲突)。