DB Migrations Using Liquibase

Pradeep Maiya
Version 1
Published in
6 min readSep 20, 2023

This documentation will explain how to achieve DB migrations to different environments with the help of the most reliable Java library “Liquibase”.

Photo by Kevin Ku on Unsplash

Table of contents :

  1. What is meant by DB migration & its use cases
  2. What is Liquibase?
  3. How to implement Liquibase in Sprint Boot
  4. Pros & Cons of Liquibase
  5. Conclusion
High-level representation of Liquibase

What is meant by DB migration & its use cases

Database migration involves transferring data from one or multiple source databases to one or multiple target databases through the utilization of a dedicated database migration service. This includes the lift & shift of database schema, tables & data (if any).

The major use cases for DB migration include system upgrades, cloud migration, and merging data from multiple systems. It's a lift & shift of data from one database server to another.

There are many libraries available in the market to achieve DB migration, one of which is using Flyway which was explained in detail in my previous blog. This documentation will briefly explain how to do DB migration using Liquibase & pros/cons of using it.

What is Liquibase?

Liquibase is an open-source database schema change management solution that enables you to manage revisions of your database changes easily. Which has built-in support for a variety of databases & can be integrated with major industry tools like Maven, Ant, Gradle, Spring Boot, and other CI/CD, etc.

Benifits of using Liquibase :

  1. Liquibase helps in the elimination of errors & delays during database releases.
  2. Liquibase helps in the smooth deploy/rollback of specific version changes without needing to know what has already been deployed.
  3. Liquibase will help keep the code base & respective environment always up to date with the latest schema changes, which makes it less error-prone during deployments.

How to implement Liquibase in Spring Boot?

This section will guide how to add Liquibase dependencies to your “pom.xml” file, and how to configure it in your “applications.properties” file, with a few more important Liquibase commands.

Adding Liquibase dependency to the “pom.xml” file :

<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>

Once the above dependency has been added, it is necessary to include configuration within the plugins section.

<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
<configuration>
<propertyFile>/src/main/resources/application.properties</propertyFile>
</configuration>
</plugin>

For “${liquibase.version}” always use the latest from the maven central repository.

Once the above dependencies are added successfully, the next step would be to add Liquibase configurations, add these configurations under the “application.properties” file :

spring.liquibase.enabled=true
spring.liquibase.defaultSchema=public
spring.liquibase.change-log=classpath:db/changelog/changelog-master.xml

spring.liquibase.change-log points to a key file that will have all the required SQL scripts file details which are part of the migration process. Create a folder under classpath/resources/db/changelog to hold all DB migrations-related files.

We need to add Liquibase plugin configurations under the “application.properties” file to apply changes against the connected database.

#mvn-liquibase
changeLogFile=src/main/resources/db/changelog/changelog-master.xml
url=jdbc:postgresql://{url}
username=
password=
driver=CONNECTED_DB_DRIVER_URL

Let’s configure the changelog-master file :

<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">
<!-- We add a new feature to the application that requires a database change, we can create a new changelog file,
add it to version control, and include it in the master changelog-->
<include file=""/>
</databaseChangeLog>

<include file=”/> tag is held responsible for adding a new entry in the “changelog-master.xml” file to hold newly added SQL scripts under the application, for every new DB schema change, there will be a new SQL file will be created with the below-given syntax. Which will have all the required DB schema changes in it.

Then a new <include> tag entry should be added under the above “changelog-master.xml” file to pick up & execute the newly added schema changes before the application starts.

The below content shows the basic syntax of adding schema changes “schema_table.sql” file :

--liquibase formatted sql
--changeset smithj:create_sample_table
--preconditions onFail:MARK_RAN, onError:MARK_RAN
--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name ='sample_table'

CREATE TABLE sample_table (
a_column VARCHAR(255)
);

--rollback drop table sample_table

In the sample above, we have defined a changeset with a unique identifier of smithj:create_sample_table (author:id). We are using the precondition-sql-check attribute to ensure that the SQL script is executed only if the defined check passes. In the event of a failure, we have chosen to mark the changeset as already executed using the MARK_RAN flag. You can learn more about preconditions here.

It is important to include the line --liquibase formatted sql at the beginning of the changelog file. This line helps Liquibase correctly parse the content of the file, including essential instructions like the changeset ID and preconditions. If this line is omitted, Liquibase may not detect the format of the file correctly, resulting in errors or unexpected behavior during execution.

Including --rollback statements are recommended to facilitate the reversal of changes if necessary.

This newly added file was then added under “changelog-master.xml” like below :

<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">
<!-- We add a new feature to the application that requires a database change, we can create a new changelog file,
add it to version control, and include it in the master changelog-->
<include file="db/changelog/changes/schema_table.sql"/>
</databaseChangeLog>

Once all the above-mentioned steps were added to the code base, When the application starts up “schema_table.sql” script will get executed first, and then after successful schema updation application boot up is initiated.

Note: Always make sure not to update an already executed “.sql” file, as there is an entry created whenever a new “.sql” file is being executed under the “databasechangelog” table with checksum associated with it. If an already executed file is altered then a checksum error will be thrown at the application boot time.

If any changes need to be done to the already executed file first remove the “databasechangelog” table entry by running the below rollback command.

mvn liquibase:rollback '-Dliquibase.rollbackCount=COUNT_NUMBER'

COUNT_NUMBER is the number of previously executed SQL scripts that you want to roll back with. In the above case, we have only one “.sql” file present, so if it needs to be removed from the “databasechangelog” table, COUNT_NUMBER will be “1”.

Note: Editing the already executed “.sql” file is not a best practice. If any changes need to be performed to the already executed file either rollback the changes and create a new “.sql” file or keep the existing one and create an altogether new “.sql” file for updating the changes.

Pros & Cons of using Liquibase

Pros :

  1. Liquibase helps in keeping track of all the DB changes that occur to the application with the help of a special table called “databasechangelog”.
  2. Easy Rollback.
  3. Database history documentation can be generated using Liquibase.

Cons :

  1. One of the biggest cons of using Liquibase is that if any change needs to be done for the already executed “.sql” file not straightforward. Since there is a database entry (checksum) for a newly executed “.sql” file under “databasechangelog” table, whenever an already executed file gets updated. Due to the updation, the checksum associated with that file gets updated which leads to a checksum error while booting up the service.

Conclusion

Having a feature to cumulatively address DB schema change makes an application more de-coupled with the added advantage of easy lift & shift of application for different various systems/environments. Implementation of Liquibase in any application will increase easy development, evolve, and ship the application which is less effort.

This documentation will demonstrate the real-world implementation of Liquibase using the Spring Boot application.

References

  1. https://www.liquibase.com/
  2. https://docs.liquibase.com/commands/change-tracking/history.html
  3. https://gitlab.version1.com/shared/foundations/accelerators/cloud-migration-discovery-tool/accelerator-cloud-migration-discovery-api/-/blob/master/docs/schema-migration.md

About the Author:
Pradeep Maiya is a Java Developer at Version 1.

--

--