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

Liquibase 4.29编程式更新及回滚支持方案咨询(Spring应用)

Liquibase 4.29编程式执行迁移方案(对齐CLI回滚效果)

一、回滚无效的核心原因

你的问题本质是Spring自动执行与CLI的Liquibase配置不一致,导致变更集记录不匹配:

  • Changelog文件路径、上下文(Contexts)、标签(Labels)参数不统一
  • Spring数据源与CLI使用的数据库连接参数不同,操作了不同的databasechangelog表

二、替代弃用update()的推荐编程式方案

使用Liquibase官方推荐的CommandScope执行迁移(CLI底层也用此逻辑),确保与CLI行为完全一致,同时在Spring启动前执行,失败则终止应用:

代码示例

import liquibase.command.CommandScope;
import liquibase.command.core.UpdateCommandStep;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;

@Component
public class LiquibaseMigrationStarter implements ApplicationListener<ApplicationStartingEvent> {

    private final DataSource dataSource;

    public LiquibaseMigrationStarter(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        try (Connection conn = dataSource.getConnection()) {
            // 初始化数据库连接与资源访问器
            Database database = DatabaseFactory.getInstance()
                    .findCorrectDatabaseImplementation(new JdbcConnection(conn));
            ClassLoaderResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor();

            // 构建Update命令,与CLI参数完全对齐
            CommandScope updateCmd = new CommandScope(UpdateCommandStep.COMMAND_NAME)
                    .addArgumentValue(UpdateCommandStep.CHANGELOG_FILE_ARG, "classpath:db/changelog/db.changelog-master.xml")
                    .addArgumentValue(UpdateCommandStep.CONTEXTS_ARG, "") // 与CLI保持一致,比如CLI用--contexts=dev则填"dev"
                    .addArgumentValue(UpdateCommandStep.LABELS_ARG, "") // 与CLI保持一致,比如CLI用--labels=v1则填"v1"
                    .addArgumentValue(UpdateCommandStep.DATABASE_ARG, database)
                    .addArgumentValue(UpdateCommandStep.RESOURCE_ACCESSOR_ARG, resourceAccessor);

            // 执行迁移,失败直接终止应用
            updateCmd.execute();
        } catch (Exception e) {
            System.err.println("Liquibase迁移失败,应用终止:" + e.getMessage());
            System.exit(1);
        }
    }
}

方案说明

  • 利用ApplicationStartingEvent确保迁移在Spring应用核心组件初始化前执行
  • 使用CommandScope完全对齐CLI的执行逻辑,保证变更集记录与CLI执行的一致
  • 捕获所有异常并调用System.exit(1),实现迁移失败则终止应用的要求

三、确保回滚与CLI一致的关键配置

  1. 统一Changelog路径:
    • Spring中用classpath:前缀(如classpath:db/changelog/db.changelog-master.xml)
    • CLI中对应使用相对路径(如src/main/resources/db/changelog/db.changelog-master.xml),或通过--classpath指定资源根目录
  2. 匹配上下文与标签:
    • 编程式执行时的CONTEXTS_ARG和LABELS_ARG必须与CLI执行update时的--contexts、--labels参数完全一致
  3. 统一数据库连接:
    • Spring数据源的URL、用户名、密码需与CLI的liquibase.properties配置完全相同,确保操作同一份databasechangelog表

四、编程式回滚示例(可选)

如果需要在代码中执行回滚,同样使用CommandScope保证与CLI效果一致:

import liquibase.command.CommandScope;
import liquibase.command.core.RollbackCommandStep;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.resource.ClassLoaderResourceAccessor;

import javax.sql.DataSource;
import java.sql.Connection;

public class LiquibaseRollbackService {

    private final DataSource dataSource;

    public LiquibaseRollbackService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void rollbackByCount(String count) throws Exception {
        try (Connection conn = dataSource.getConnection()) {
            Database database = DatabaseFactory.getInstance()
                    .findCorrectDatabaseImplementation(new JdbcConnection(conn));
            ClassLoaderResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor();

            CommandScope rollbackCmd = new CommandScope(RollbackCommandStep.COMMAND_NAME)
                    .addArgumentValue(RollbackCommandStep.CHANGELOG_FILE_ARG, "classpath:db/changelog/db.changelog-master.xml")
                    .addArgumentValue(RollbackCommandStep.ROLLBACK_COUNT_ARG, count)
                    .addArgumentValue(RollbackCommandStep.CONTEXTS_ARG, "")
                    .addArgumentValue(RollbackCommandStep.LABELS_ARG, "")
                    .addArgumentValue(RollbackCommandStep.DATABASE_ARG, database)
                    .addArgumentValue(RollbackCommandStep.RESOURCE_ACCESSOR_ARG, resourceAccessor);

            rollbackCmd.execute();
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:56:05