Evolving your database in a Spring Boot Application with Liquibase
Liquibase enables you to go faster and automate your processes by tracking, versioning and deploying database changes.
Why do you need Liquibase ?
- Deploying/rollbacking database changes seemingly and easy integration with your CD pipeline
- Creating a new environment/sql schema by only running a command
- Versioning changes and migration in your database
- Auditing database changes
How does it works ?
Liquibase uses a table databasechangelog
to track all the changes, which will be created the first time Liquibase runs.
Each change/migration will be audited in a table, and information such as id
, author
, filename
and many more will be stored.
Another table called databasechangeloglock
is created, which will ensure that only one instance of Liquibase is running at a time so that no conflict will happen during the migration.
How to set it up ?
Add the following dependencies
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency><dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
</dependency>
Add the following plugin
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
<configuration>
<propertyFile>${liquibase.propertyFile}</propertyFile>
<promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
</configuration>
</plugin>
liquibase.properties
file contains
- database information such as
url
,username
,password
,driver
changelog
file location
Here is an example of a liquibase.properties
file
Changelog
All Liquibase changes are logged through a changelog
file : changelog-master.yaml
, which will list sequentially all the changes made to the database.
Here is an example
databaseChangeLog:
- include:
file: src/main/resources/db/changelog/0001/changelog.yaml
- include:
file: src/main/resources/db/changelog/0002/0002-01_create_new_table.sql
Changeset
The changeset
is a unit of change which is identified by an id and an author.
A changeset
can be written in XML
, JSON
, SQL
, YML
, here is a how a changeset
written in SQL will look:
--liquibase formatted sql
--changeset author:idCREATE TABLE ...-- rollback DROP TABLE ...;
So let’s say you want to create a new table product
that have a new a sequence as a primary key. Here is how this change will look with a SQL
format changeset
:
--liquibase formatted sql
--changeset eliedaher:1CREATE SEQUENCE product_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;CREATE TABLE product (
id INTEGER NOT NULL DEFAULT NEXTVAL('product_id_seq') PRIMARY KEY,
key CHARACTER VARYING(64),
description CHARACTER VARYING(255)
);-- rollback DROP TABLE product;
-- rollback DROP SEQUENCE product_id_seq;
Use cases
Here is the most used commands in Liquibase
Update on database
Updating allows us to deploy all the changeset
that are not yet executed
mvn liquibase:update
Tag current database state
Tagging allows us to version database states, so that we can rollback to a previous state easily in future
mvn liquibase:tag -Dliquibase.tag=10
Rollback by changeset count
mvn liquibase:rollback -Dliquibase.rollbackCount=2
Rollback to a specific date
mvn liquibase:rollback -Dliquibase.rollbackDate=2021-04-30T11:30:00
Rollback to a previous tag
mvn liquibase:rollback -Dliquibase.rollbackTag=9
Check all other commands here
Some tips
Use SQL instead of other format
Changes can be written in XML
, JSON
, SQL
, YML
. In all the projects that I worked on, we chose SQL
since it is well known by most of the contributors of our projects and no learning curve was needed to master it.
Organising changesets by feature
The way I usually organise the changesets
is by creating a folder for each new feature, with the folder being identified by a feature id, that way each feature will have it’s own changelog
file.
By doing that, the changelog-master
will contain a list of features changelogs
.
Disabling automatic migration
Whenever you compile the spring boot application, Liquibase will run its migration. So instead of enabling that feature, I opt out to disable it, and run the migration as a dedicated task by itself.
The way to disable database migration on each compilation is by setting the following property to false
:
spring.liquibase.enabled=false
Liquibase has improved the way we worked and allowed us to evolve and perform migration on our database seemingly. Other alternatives on the market are available, such as Flyway, which does the job.
An example of integrating Liquibase in a spring boot application is present here.
Feel free to comment, if you have any question or if I missed something 😬.