In our previous blog post, we describe how we can conditionally prepare for database state to determine certain conditions and then only proceed to deploy our changes. This prevents us from doing errors like inserting the same record again or dropping a table full of records. However, irrespective of our precautionary measures, mistakes are bound to happen. So we need to prepare for those eventualities as well. This may also be needed if you roll out certain changes and found that those changes were inadequate to resolve the matter at hand. In liquibase, we can prepare for these kind of scenarios using the concept of rollback and tags.
Rolling Back Database Changes
Database change rollbacks can be done if:
- The rollback command is already included in the changeset
- The rollback is performed to:
- to change the database state back to a previous date/time
- to change the database to a previous state marked by a “tag”
- to change the database to a state that existed a number of changesets before
To perform the rollback successfully, we need first point to be true and one of the conditions mentioned in the second point to be true.
We do not need to perform or specify rollbacks, where it is automated and implicit because of the inherent nature of the underlying DBMS. For example, suppose that you are inserting a row and it fails a table level constraint such as with primary or foreign key, the INSERT statement will be automatically rolled back. However this is not true if you are inserting a bunch of rows and it fails for only a couple of them. In such a case, only those two will be auto rolled back but others will pass through. Some databases like PostgreSQL follows the ACID principal for DDL statements as well while others not. So overall the point is that, we do not need to worry about rollbacks if they are implicit in nature of the underlying DBMS.
Perform Database Tagging
A tag is nothing but a marker for the database at any particular point in time. A tag is given so when rolling back, we can always go back to that tag. The command below shows how we are creating the tag:
All we need to do is to use a tag command along with the name of the tag. Alternatively, if all of the required parameters are mentioned in the liquibase.properties file like below, then we can just use
liquibase tag :
If we take a look at the DATABASECHANGELOG table, we can see that we now have the tag value filled in at last liquibase change record:
Perform and rollout Database Change
Now, let’s say that our next change consists of creating a table named CustomerDetails5 and the changeset has been defined as below:
We have defined what to do in case of rollback using ––rollback switch.
Let’s go ahead and apply this change using
And verify that it has been created in the database:
Perform rollback using Database Tag
Now let’s say for some reason the table creation was something that we did not want in our database and we would like to roll it back. Remember we had tagged our database before we ran this changeset. We can roll our database back to that tag using the command
liquibase rollback in below manner:
liquibase rollback dbchange-ci-188.8.131.52
Below is the output of the command in above case:
Why did it failed to rollback? As we mentioned that for rollback to be successful, liquibase must have associated rollback statement with the changeset. In our case, we did specified rollabck statement with changeset 20190309122800 but not with changeset 20190309175300.
Let’s correct our changset to include rollback statements for both of above changesets as below:
Apply our change and then we can perform rollback with using tagname. Now, it will be successfully rolled back:
On successful rollback, associated change records would also be gone from the DATABASECHANGELOG table:
Perform rollback up to point in time
What happens if we forgot to tag the database before the stored procedure was created? We could always use the rollbackToDate command and use the date time of the changeset we wanted to roll back to:
liquibase rollback rollbackToDate
Full command is as below:
Other variations of rollback
Liquibase supports variety of commands on rollback as below:
|rollback||Rolls back the database to the state it was in when the tag was applied.|
|rollbackToDate||Rolls back the database to the state it was in at the given date/time.|
|rollbackCount||Rolls back the last change sets.|
|rollbackSQL||Writes SQL to roll back the database to the state it was in when the tag was applied to STDOUT.|
|rollbackToDateSQL||Writes SQL to roll back the database to the state it was in at the given date/time version to STDOUT.|
|rollbackCountSQL||Writes SQL to roll back the last change sets to STDOUT|
|futureRollbackSQL||Writes SQL to roll back the database to the current state after the changes in the changeslog have been applied|
|updateTestingRollback||Updates the database, then rolls back changes before updating again|
|generateChangeLog||generateChangeLog of the database to standard out|
So we have quite a few options there.