Rodolfo
Rodolfo

Reputation: 511

Liquibase rollback from command line not working

I am doing an tomcat appliaction in a windows enviroment that when deployed creates/updates the DB Schema on the oracle db. For this I am using the Liquibase SDK 3.3.2. So basically I call the SDK an tell it to do an update from my changelog.xml. This parts works as fine. The code form the java class

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

liquibase.update("");

The problem is, when something goes wrong and I do a Rollback from the command line nothing happens. I get no exceptions or error messages. Just a message "Rollback succesfull", but in the DB there is no change at all. Now the funny thing is when I do the update for my change log file from cmd and then do the rollback also from the cmd then the Rollback works. The command line call looks as following:

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

My liquibase.properties file looks as following:

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

The question does some know why does this happens? Are there any incompatibilties between SDK and cmd tool?

Upvotes: 4

Views: 6953

Answers (3)

Amrish
Amrish

Reputation: 697

This same issue happened to me. As stated, the classpath reference for liquibase runner was different when executed via SpringBoot application vs Gradle task. In order to fix it I had to add the following to my dependencies closure in my build.gradle file.

liquibaseRuntime files("src/main/resources")

Adding this seems like fix the issue.

Upvotes: 0

Nabil_H
Nabil_H

Reputation: 391

For the benefit of other readers, I'd like to add my experiences and understanding.

It's important to understand what is happening when you run a rollback from the command line

  • Liquibase consults the changelog file you provided via the --changeLogFile argument.

  • It will iterate through the changesets mentioned in this file, comparing their checksum to the checksum for the corresponding record in the DATABASECHANGELOG database table.

  • Now here's the important bit: the checksum is calculated from the filename (including the path) and the file contents.

  • If the checksums do not match, the changeset is not eligible for rollback.

  • If you ran Liquibase from inside a web-application, the chances are that the Liquibase changelog was located on the classpath, which means that the filename column in the DATABASECHANGELOG table is prefixed with classpath:

ID                  AUTHOR   FILENAME                                          
CreateWidgetTable   NabilH   classpath:liquibase/sprint1/create.widget.table.xml
  • This is not the case when you run via the command line

  • This will cause the checksum validation to fail and changeset to be ignored

However, I think there is a better solution than what you have proposed. You can point the --classpath argument of Liquibase command line at your WAR, and specify the --changeLogFilePath relative to the classpath.

Assume that I store my changelog in src/main/resources/liquibase/changelog.xml.

On the classpath therefore, this file is accessible via 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

Upvotes: 4

Rodolfo
Rodolfo

Reputation: 511

The problem was the path to the change log file. Liquibase stores somewhere the path to the chengeLog and comapres it to the given change log at calling. If they are not the same Liquibase will just go on without a changeLog and warning.

So in my case when calling Liquibase from the tomcat app the path was: database\master.xml and when calling it from the console I gave the path C:\myProject\src\main\resources\database\master.xml in the comand line. This caused the method to return null although Liquibase knew the path to the changeLog. So that was the reason it did not worked.

A workaround is to call liquibase from the command line from the same folder as the application did using a relative path.

Technical reason: After debuggin LB I found this. The Method DatabaseChageLog.getChangeSet() is returning null althoug the chanegeLog path is correct. This happens when creating the ChangeLogIterator for runnign the RollbackVisitor in the method Liquibase.rollback(int changesToRollback, Contexts contexts, LabelExpression labelExpression). This do not happens with the ValidationVisitor becasuse the ChangeLogIterator is created differently, that is why I did not get any error\warnings

Upvotes: 9

Related Questions