Liquibase 4.21.1调用Context的正确方式及Java API问题
Liquibase 4.21.1 Java API 执行多上下文Schema更新方案
问题分析
你遇到的核心问题有两个:
- 旧版
liquibase.update()方法已弃用,需用CommandScope替代 - 误用
UpdateSqlCommandStep只会生成变更SQL但不实际执行,导致锁表未真正创建,后续操作报错
正确实现方案
Liquibase 4.x推荐用CommandScope执行命令,但要注意使用**UpdateCommandStep.COMMAND_NAME**(执行变更)而非UpdateSqlCommandStep.COMMAND_NAME(仅生成SQL)。以下是完整可运行示例:
1. 完整代码示例
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 java.sql.Connection; import java.sql.DriverManager; public class LiquibaseSchemaUpdater { private static final String CHANGELOG_PATH = "db/changelog/db.changelog-master.xml"; // 替换为你的changelog路径 public static void main(String[] args) throws Exception { // 初始化数据库连接 String url = "jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC"; String username = "root"; String password = "password"; Connection connection = DriverManager.getConnection(url, username, password); // 创建Liquibase Database对象 Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); // 依次执行两个上下文 applyContextTransaction(database, "createAndInitializeDb"); applyContextTransaction(database, "update"); // 关闭资源 connection.close(); } private static void applyContextTransaction(Database db, String context) throws Exception { System.out.println("开始执行上下文: " + context); // 使用UpdateCommandStep执行实际变更,而非生成SQL CommandScope updateCommand = new CommandScope(UpdateCommandStep.COMMAND_NAME); updateCommand.addArgumentValue("database", db); updateCommand.addArgumentValue("changelogFile", CHANGELOG_PATH); updateCommand.addArgumentValue("contexts", context); // 添加资源访问器,确保Liquibase能找到changelog文件 updateCommand.addArgumentValue("resourceAccessor", new ClassLoaderResourceAccessor()); // 执行命令 updateCommand.execute(); System.out.println("上下文执行完成: " + context); } }
2. 关键修正点
- 替换命令类型:把
UpdateSqlCommandStep.COMMAND_NAME改为UpdateCommandStep.COMMAND_NAME,后者才会真正执行数据库变更操作 - 添加资源访问器:通过
ClassLoaderResourceAccessor让Liquibase正确加载classpath下的changelog文件 - 连接管理:确保数据库连接初始化正确,执行完成后关闭资源
3. 注意事项
- 如果changelog文件不在classpath下,可替换为
FileSystemResourceAccessor并传入绝对路径 - 若需自定义事务行为,可通过
Scope.getCurrentScope().getDatabase().getConnection().commit()手动控制,但Liquibase默认会在每个变更集执行后自动处理事务 - 执行两个上下文时请使用同一个
Database对象,避免锁表冲突
内容的提问来源于stack exchange,提问作者jithk
相关产品推荐
相关产品推荐

