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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
:

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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
— 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
:
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-1.0.0.219
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
— 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:
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
[…] the last line contains the rollback statement to be used. More details on rollback are covered in this […]
LikeLike
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.
LikeLike