Prepare failback strategy for database changes with Liquibase

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:

  1. The rollback command is already included in the changeset
  2. The rollback is performed to:
    1. to change the database state back to a previous date/time
    2. to change the database to a previous state marked by a “tag”
    3. 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:


liquibase
–driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
–classpath="C:\\Program Files\\Microsoft JDBC Driver 6.0 for SQL Server\\sqljdbc_6.0\\enu\\jre8\\sqljdbc42.jar"
–url="jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks2017;integratedSecurity=false;"
–changeLogFile="D:\Source\generateChangeLog.xml"
–username=liquibase
–password=liquibase@123
–logLevel=info
tag dbchange-ci-1.0.0.219

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 :

tagging database using liquibase
tagging database using liquibase

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:

verifying tag value from the databasechangelog table

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:


— liquibase formatted sql
— changeset mohitgoyal:20190309122800
CREATE TABLE [AdventureWorks2017].[dbo].[CustomerDetails5](
[CustomerTypeID] [nchar](10) NULL,
[CustomerDesc] [nvarchar](max) NULL,
[CustomerAddress] [varchar](255) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
–rollback drop table CustomerDetails5
— changeset mohitgoyal:20190309175300
insert into CustomerDetails5 values ('A','CustomerA','SanDiego')
insert into CustomerDetails5 values ('A','CustomerB','Miami')

We have defined what to do in case of rollback using ––rollback switch.

Let’s go ahead and apply this change using liquibase update:

applying changelog using liquibase

And verify that it has been created in the database:

verify table has been created using liquibase

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-1.0.0.219

Below is the output of the command in above case:

failed rollback using liquibase

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:


— liquibase formatted sql
— changeset mohitgoyal:20190309122800
CREATE TABLE [dbo].[CustomerDetails5](
[CustomerTypeID] [nchar](10) NULL,
[CustomerDesc] [nvarchar](max) NULL,
[CustomerAddress] [varchar](255) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
–rollback DROP TABLE [dbo].[CustomerDetails5]
— changeset mohitgoyal:20190309175300
insert into CustomerDetails5 values ('A','CustomerA','SanDiego')
insert into CustomerDetails5 values ('A','CustomerB','Miami')
— rollback delete from CustomerDetails5

Apply our change and then we can perform rollback with using tagname. Now, it will be successfully rolled back:

successful rollback using liquibase command

On successful rollback, associated change records would also be gone from the DATABASECHANGELOG table:

verifying tag value 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:


liquibase
–driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
–classpath="C:\\Program Files\\Microsoft JDBC Driver 6.0 for SQL Server\\sqljdbc_6.0\\enu\\jre8\\sqljdbc42.jar"
–url="jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks2017;integratedSecurity=false;"
–changeLogFile="D:\Source\generateChangeLog.xml"
–username=liquibase
–password=liquibase@123
–logLevel=info
rollback rollbackToDate 2019-03-09 00:40:30.617

Other variations of rollback

Liquibase supports variety of commands on rollback as below:

Command Description
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.

2 thoughts on “Prepare failback strategy for database changes with Liquibase

  1. Is it possible to use rollback using spring boot ,and there should not be any command line interface.. everything should be automated. For example, I have written 5 changeset,and have drop statements too,i have created tags also before every changeset.

    I want to perform rollback, just running the spring boot application.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s