Spring Boot Liquibase Tutorial
Tutorial: use Liquibase with Spring to update your database
In this example we look at the integration between liquibase and Spring Boot. We will create a basic example with scripts that will run in a memory H2 database for the local environment and in PostgreSQL for the 'production'.
What you can find in the post:
- integration of liquibase with Spring Boot
- deployment of the same scripts for H2 in memory database for local development and PostgreSQL for production
- configuration using XML and SQL to avoid SnakeYml issues
- call of multiple liquibase databaseChangeLog in hierarchy
To reduce the depencies to external libraries (and issues) we won't use Liquibase Client and we will configure the application and liquibase using simple SQL and XML.
We could not se yaml or json because of a security issue in SnakeYaml (1.3) that is used by Liquibase to parse yaml and JSON. The issue is fixed with SnakeYML 2.0 but this library was not compatible with Spring Boot 3.0.x yet.
- Structure of the project
- Database scripts
- Liquibase configuration
- Spring Boot configuration
The complete code of the application is available here:
https://github.com/marco76/LiquibaseDemo
Liquibase files
In our structure we have 2 main changelogs. db.changelog-h2.xml
is used for the local dev environment (memory database). Every time we start the application we have the same fresh data in memory.
For the instances of integration and production we use a PostgreSQL database. These environments use the db.changelog-postgresql.xml
file.
The script for PostgreSQL and H2 are the same, the small differences are integrated in h2-function.sql
that convert some PostgreSQL features in H2.
Liquibase H2 Changelog
<include file="/db.changelog/changes/h2-functions.sql"/>
<include file="/db.changelog/db.changelog-postgresql.xml" />
<includeAll path="/db.changelog/changes/h2-data/"/>
The H2 Changelog:
- import some functions in h2 that are not available by default
- executes the 'official' changelog, the one for PostgreSQL
- load the data in the database for the local/dev environment
Liquibase PostgreSQL Changelog
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
<include file="/db.changelog/changes/schema.sql"/>
</databaseChangeLog>
The PGSQL changelog load the schema files that will contains all the changes to apply in the DB. We opted to have only 1 file with multiples changesets
but you could split the changes in multiples files.
The content of the schema.sql
:
-- liquibase formatted sql
-- changeset marco:1
CREATE TABLE PERSON
(
ID UUID not null default gen_random_uuid(),
NAME VARCHAR not null
);
SpringBoot and Liquibase
To load The Liquibase data in our H2 Database we need to add some dependecies in our pom.xml
:
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
You should add the dependency of your production DB too (in our case PostgreSQL).
Spring Boot recognize H2 and Liquibase and try to autoconfigure them automatically.
H2 DB configuration
spring.datasource.url=jdbc:h2:mem:db;MODE=PostgreSQL;Database_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=TRUE;
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.sql.init.platform=h2
spring.jpa.hibernate.ddl-auto=none
spring.liquibase.change-log=classpath:/db.changelog/db.changelog-h2.xml
In the configuration of our H2 database we add the reference to the spring.liquibase.change-log
file. This triggers the scripts when the application starts.
Start the application
When you start the application you should see in the log that the database has been correctly loaded/updated:
2023-03-27T22:42:25.510+02:00 INFO 68851 --- [ main] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/console'. Database available at 'jdbc:h2:mem:db'
2023-03-27T22:42:25.731+02:00 INFO 68851 --- [ main] liquibase.database : Set default schema name to public
2023-03-27T22:42:25.889+02:00 INFO 68851 --- [ main] liquibase.lockservice : Successfully acquired change log lock
2023-03-27T22:42:26.273+02:00 INFO 68851 --- [ main] liquibase.changelog : Reading resource: db.changelog/changes/h2-data/001-dev-data.sql
2023-03-27T22:42:26.298+02:00 INFO 68851 --- [ main] liquibase.changelog : Creating database history table with name: public.DATABASECHANGELOG
2023-03-27T22:42:26.305+02:00 INFO 68851 --- [ main] liquibase.changelog : Reading from public.DATABASECHANGELOG
Running Changeset: db.changelog/changes/h2-functions.sql::1::marco
2023-03-27T22:42:27.147+02:00 INFO 68851 --- [ main] liquibase.changelog : Custom SQL executed
2023-03-27T22:42:27.148+02:00 INFO 68851 --- [ main] liquibase.changelog : ChangeSet db.changelog/changes/h2-functions.sql::1::marco ran successfully in 777ms
Running Changeset: db.changelog/changes/schema.sql::1::marco
2023-03-27T22:42:27.202+02:00 INFO 68851 --- [ main] liquibase.changelog : Custom SQL executed
2023-03-27T22:42:27.203+02:00 INFO 68851 --- [ main] liquibase.changelog : ChangeSet db.changelog/changes/schema.sql::1::marco ran successfully in 6ms
Running Changeset: db.changelog/changes/h2-data/001-dev-data.sql::1::marco
2023-03-27T22:42:27.211+02:00 INFO 68851 --- [ main] liquibase.changelog : Custom SQL executed
2023-03-27T22:42:27.211+02:00 INFO 68851 --- [ main] liquibase.changelog : ChangeSet db.changelog/changes/h2-data/001-dev-data.sql::1::marco ran successfully in 6ms
2023-03-27T22:42:27.215+02:00 INFO 68851 --- [ main] liquibase.lockservice : Successfully released change log lock
When the application runs you can check that 3 tables exists in the h2 console:
Person
is our business table, Liquibase created 2 additional tables to manage the scripts, for us is interesting databasechangelog
where we can see the changes loaded in the database:
The SnakeYML issue
The SnakeYML issue. Liquibase (and SpringBoot) has dependencies with SnakeYML 1.33 that has been affected by a security issue.
Some production environments don't allow the deployment of 'unsafe' libraries. For this reason we implemented the code using XML and SQL. Liquibase uses SnakeYML 1.33 as yaml and JSON parser.