从命令行回滚 Liquibase 不起作用

Liquibase rollback from command line not working

我正在 windows 环境中执行 tomcat 应用程序,当部署时 creates/updates 数据库架构在 oracle 数据库上。为此,我使用 Liquibase SDK 3.3.2。所以基本上我调用 SDK 并告诉它从我的 changelog.xml 进行更新。这部分工作正常。 代码形式 java class

...
Liquibase liquibase = new Liquibase(CHANGE_LOG,
                new ClassLoaderResourceAccessor(getClass().getClassLoader()), db);

liquibase.update("");

问题是,当出现问题并且我从命令行执行回滚时,什么也没有发生。我没有收到任何异常或错误消息。只是一条消息 "Rollback succesfull",但在数据库中根本没有任何变化。现在有趣的是,当我从 cmd 更新我的更改日志文件,然后也从 cmd 执行回滚时,回滚工作。命令行调用如下所示:

Liquibase --changeLogFile=C:\myProject\src\main\resources\database\master.xml  --logLevel=DEBUG rollbackCount 5

我的 liquibase.properties 文件如下所示:

driver: oracle.jdbc.OracleDriver 
classpath:ojdbc6.jar 
url: jdbc:oracle:thin:@192.168.56.101:1521:orcl
username: myUser
password: mypassword

问题有人知道为什么会这样吗? SDK 和 cmd 工具之间是否存在不兼容问题?

问题出在更改日志文件的路径上。 Liquibase 在某处存储到 chengeLog 的路径,并在调用时将其映射到给定的更改日志。如果它们不相同,Liquibase 将在没有更改日志和警告的情况下继续进行。

所以在我的例子中,当从 tomcat 应用程序调用 Liquibase 时,路径是:database\master.xml 并且从控制台我在命令行中给出了路径 C:\myProject\src\main\resources\database\master.xml 。这导致该方法为 return null,尽管 Liquibase 知道更改日志的路径。所以这就是它不起作用的原因。

解决方法 是从与应用程序使用相对路径相同的文件夹的命令行调用 liquibase。

技术原因: 在 debuggin LB 之后我发现了这个。方法 DatabaseChageLog.getChangeSet() 是 returning null 尽管 changeLog 路径是正确的。在方法 Liquibase.rollback(int changesToRollback, Contexts contexts, LabelExpression labelExpression)ValidationVisitor 不会发生这种情况,因为 ChangeLogIterator 的创建方式不同,这就是为什么我没有得到任何 error\warnings [=10] =]

为了其他读者的利益,我想补充一下我的经验和理解。

了解当您运行从命令行

回滚时发生的事情很重要
  • Liquibase 参考您通过 --changeLogFile 参数提供的变更日志文件。

  • 它将遍历此文件中提到的变更集,将它们的校验和与 DATABASECHANGELOG 数据库 table.

    中相应记录的校验和进行比较
  • 现在重要的一点是:校验和是根据文件名(包括路径)和文件内容计算的。

  • 如果校验和不匹配,则变更集不符合回滚条件。

  • 如果您从 Web 应用程序内部 运行 Liquibase,Liquibase 变更日志很可能位于类路径中,这意味着 DATABASECHANGELOG table 以类路径为前缀:

ID                  AUTHOR   FILENAME                                          
CreateWidgetTable   NabilH   classpath:liquibase/sprint1/create.widget.table.xml
  • 当你通过命令行运行

  • 时情况并非如此
  • 这将导致校验和验证失败并忽略变更集

但是,我认为有比您提出的更好的解决方案。您可以将 Liquibase 命令行的 --classpath 参数指向您的 WAR,并指定相对于类路径的 --changeLogFilePath

假设我将更新日志存储在 src/main/resources/liquibase/changelog.xml 中。

因此,在类路径上,可以通过 liquibase/changelog.xml.

访问此文件
java -jar lib/liquibase-core-3.5.3.jar\
    --url=jdbc:h2:tcp://localhost/~/test --username=sa --password=\
    --logLevel=DEBUG --classpath=/opt/tomcat9/webapps/springLiquibase.war\
    --changeLogFile=liquibase/changelog.xml rollback v1