Migrating an application to a new framework is mostly painful and challenging. We started to migrate our existing Jakarta EE applications
which have been using Liquibase to manage the database changes. Quarkus has native support for Flyway
which is another tool to manage the database changes. One option was to migrate the Liquibase change log file to Flyway SQL.
Liquibase is also widely used in open source community, and has some advantages that you may find useful in daily DevOps processes.
We chose to stay with Liquibase and minimize the changes in the projects. Native support for Liquibase would be highly favorable to avoid
another Java JDK dependency in the Docker environment. So we started to create Liquibase extension for Quarkus.
Quarkus Kubernetes native Java stack comes with an extendable framework. There is a very nice guide on Quarkus
page how to write your own extension. We are already using our own extensions for logs,
Java Persistence API (JPA) and testing specific to our projects and needs. But much more exciting is to write an extension that would become a part of the Quarkus and would contribute to the open source
community. I believe we are not the only ones who have been using the Liquibase framework to manage database changes in recent
years in projects. With the help of Quarkus and Liquibase community, we designed and implemented the Liquibase extension which is now
part of Quarkus framework. In this article we are going to create an example Quarkus Application which will show
how to use this Liquibase extension.
Quarkus Liquibase extension
In our example we will use Maven to manage the project. First, we will create simple REST + JPA application.
For this we can use the Quarkus maven plugin:
The project structure is created and we can add our JPA model for Event.
The REST controller for the Event resource will have methods for create, findByGuid and findAll.
In the next step we need to set up the database connection in our application.properties.
For the local development we will use the PostgreSQL Docker image to run the database server.
The newly created database is still empty. Now we can add the Liquibase extension to our project. Just add this Maven dependency:
For our database changes we need to put the changeLog.xml file in the src/main/resources/db/ directory.
In the changeLog we can use the includes and the other formats yaml, json and sql are also supported.
You can create the file by hand or also use a generator to evaluate the recent changes of the entity model.
To update our database schema automatically at the start of the application add this property quarkus.liquibase.migrate-at-start
in the application.properties and set its value to true. This will start the migration during the starting of the application.
Now we can start the application in development mode
From the logs we can see that Liquibase runs the database update. In the database we will have new table
and we can start to create objects. Let’s create event in the database.
Output:
We can load the data through this command
Output:
We have data in the table, now we are going to add new fields. First we need to update the Java class and add field and
getter and setter.
Next step would be to add the changeSet in our changeLog.xml.
One of Quarkus benefits is that we do not need to restart the application just to make a call to get our object through the
rest interface and Quarkus will do the job for us and run the latest version of our application with database update.
Output:
From the output, we can see that the model has a new field and also the database table has been updated. Another useful configuration
are drop all tables before migration, disable Liquibase validation and changeLog file path.
Also, you can use Liquibase directly in the application. We need to inject LiquibaseFactory and create the Liquibase object.
For example we can create the REST controller to return all run changes.
To get all executed changes from Liquibase we need to call this URL:
Then we will get output like this:
Now Quarkus provides first class support for using Liquibase as will be explained in the Liquibase guide.
All this configuration can be found in the Quarkus Liquibase guide
We have also use cases where we need to run Liquibase separately from the microservice. One option is to install Liquibase
directly but in the case we have native application we want to avoid a JVM installation. For this case, we created
the Liquibase native build (currently only for PostgreSQL database and Linux) which can be downloaded from
1000kit-liquibase
This Liquibase binary is also provided as a base Docker image which you can use in your docker image.
1000kit/liquibase Docker image as build image.
The source code of the example is in the github repository 1000kit/quarkus-liquibase-example
where we need to first build the native application.
Then we can build the Docker image with native Liquibase inside and copy the Liquibase changelog files
also in the Docker image.
The CMD command of the Docker image will run Liquibase before the application and the Liquibase configuration is using the standard Quarkus environment variables for the database connection.
For testing, use the docker-compose.yml which is in the git repository. First start the database and the application.
The database connection for the application and for Liquibase is configured in the docker-compose.yml file.
The environment variable QUARKUS_LIQUIBASE_MIGRATE_AT_START is setup to false and it will disable running Liquibase
second time by the Quarkus Liquibase extension. The output of the application will look like this:
I hope that this extension will be useful for other teams - if you’re building Quarkus applications that work with Liquibase,
please try it out, and if you use it on your project, I’d love to hear about it.