You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Liquibase至4.21.1后出现ChangeSet ID重复问题求助

Liquibase升级后重复变更集验证失败的解决方案

问题背景

把使用Liquibase 4.9.1的Spring Boot 2.7.x项目升级到包含Liquibase 4.21.1的最新Spring Boot版本后,启动系统抛出以下异常:

Caused by: liquibase.exception.ValidationFailedException: Validation was unsuccessful:
840 change sets had duplicate identifiers

问题源于多模块项目中Liquibase XML文件互相引用的结构,示例如下:

<!-- db/migration/changes/second.changelog.xml -->
...
<include file="/db/migration/changes/first.changelog.xml" />
...

升级前运行正常,升级后出现上述问题,已尝试以下方案:

  • 跳过重复变更集验证:通过断点修改liquibase.changelog.visitor.ValidatingVisitor::validationPassed()返回true,结果脚本执行两次,出现表已存在的SQL错误
  • 移除引用:可解决重复问题,但Liquibase无法按正确顺序执行文件,集成测试因脚本依赖缺失失败
  • 移除引用并在db.changelog-master.yaml中显式列出变更日志:方案可行,但无法通过Spring Profiles激活/停用单个变更日志,不适用于集成测试场景

原因分析:Liquibase的重复项处理逻辑变更

Liquibase从4.10版本开始,对变更集的重复验证逻辑做了严格强化:

  • 旧版本(4.9及以下)允许变更集被多次include,只要变更集的执行状态已记录在数据库的DATABASECHANGELOG表中,就会跳过重复执行,且不会触发验证报错
  • 新版本(4.10+)默认会扫描整个变更日志树,检测到同一个变更集(通过id+author+filepath唯一标识)被多次引用时,直接抛出ValidationFailedException,阻止系统启动

解决方案

方案1:使用includeAll配合上下文(Contexts)替代互相引用

既能保留多模块的依赖逻辑,又能避免重复引用问题:

  1. 为每个模块的变更日志添加专属的Spring Profile/Context标识,比如在变更集中设置:
    <changeSet id="init-user-table" author="dev" context="user-module">
        <!-- 变更内容 -->
    </changeSet>
    
    或者在changelog根节点统一配置:
    <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.21.xsd"
                       context="order-module">
        <!-- 模块下的变更集 -->
    </databaseChangeLog>
    
  2. 在db.changelog-master.yaml中使用includeAll按目录加载变更日志,同时通过Spring Profiles控制激活的Context:
    databaseChangeLog:
      - includeAll:
          path: classpath:/db/migration/changes/
          contextFilter: ${spring.profiles.active}
    
  3. 启动时通过spring.profiles.active指定要激活的模块,Liquibase会自动加载对应Context的变更日志,不会出现重复引用的问题

方案2:使用preConditions控制引用的执行时机

在被引用的changelog中添加前置条件,确保只有当目标变更集未执行过时才加载:

<!-- first.changelog.xml -->
<preConditions onFail="MARK_RAN">
    <not>
        <changeSetExecuted id="init-base-table" author="your-name" />
    </not>
</preConditions>

这样即使被多次include,只要目标变更集已执行过,就会跳过加载,避免重复验证报错

方案3:启用宽松验证模式(不推荐)

通过配置参数关闭重复变更集的验证,在application.yml中添加:

liquibase:
  parameters:
    liquibase.validate.duplicateChangeSets: false

注意:此方案会退回到旧版本的行为,可能导致变更集重复执行的风险,仅适合临时应急使用

内容的提问来源于stack exchange,提问作者RiVogel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:07:48