1. Overview

Database schema migration is performed on a database whenever it is necessary to update/revert changes in the database or need to migrate the database from one version to other. There are two major migration tools: Liquibase, Flyway.

In this tutorial, we will go with the Liquibase.  The Liquibase is open source tool for database schema migration or database version controlling. It supports most of the major databases and different type of format for schema change file like XML, SQL, YAML, JSON. It is database vendor independent means it does not depend on any DB specific syntax. It can generate database change documentation.

In this tutorial, we will learn how to configure Liquibase with Spring Boot project. Here, we will write database schema changes in XML format. Those schema changes will be automatically performed on the configured database using liquibase when spring boot project will be started.

Here, we will consider 3 simple database operations:
1). Create table,
2). Insert data into table and
3). Update data on precondition.
Those operations will be executed by liquibase on H2 database with spring boot.

2. Example

2.1 Project Structure

Project Structure for Spring Boot with Liquibase

Project Structure for Spring Boot with Liquibase

2.2 POM file configuration

Add dependencies liquibase-corespring-boot-starter-jdbc for Liquibase support. The h2 dependency added for in-memory H2 database on which we will perform DB operations.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javadeveloperzone</groupId>
    <artifactId>liquibase</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>liquibase</name>
    <description>Demo project for Spring Boot and Liquibase</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.3 application.properties

Change log file is the main point from where Liquibase looks for configuration. If we do not define change log file path in Spring Boot, it considers db/changelog/db.changelog-master.yaml as default path for YAML format.  As we will go with XML format, we need to set spring.liquibase.change-log=classpath:/db/changelog/changelog-master.xml for change log file path in application.properties file. You can set logging level of liquibase logs by setting log level in logging.level.liquibase property. Other properties in given below properties file are for H2 database configuration.

spring.liquibase.change-log=classpath:/db/changelog/changelog-master.xml
logging.level.liquibase = INFO

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test;
spring.datasource.username=sa
spring.datasource.password=sa
spring.h2.console.enabled=truel

2.4 Change Log Files

2.4.1 changelog-master.xml

First, create the master change log file changelog-master.xml with default liquibase XML format at configured change log path. We can define all changes in one master file but it can be hard to manage after the huge number of changes. So, we will define each changeSet in different change log file and that change files will be included in master change log file by <include> tag as per below. The ordering of included file should be always in correct sequence.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <include file="/db/changelog/changes/create-person-table-changelog-1.xml"/>
    <include file="/db/changelog/changes/insert-person-table-changelog-2.xml"/>
    <include file="/db/changelog/changes/update-person-table-precondition-3.xml"/>
</databaseChangeLog>

2.4.2 create-person-table-changelog-1.xml

Now create first change log file create-person-table-changelog-1.xml at shown in the path above file. The <databaseChangeLog> tag must be the root element in every change log file. Write database related operation in <changeSet> tag with author and unique id attribute in liquibase defined XML syntax.  As per best practice, write one change per changeSet to avoid failed auto-commit statements. Below, changeSet will create table person with three columns named id, name and address in the test H2 database. We can also perform a rollback on changes performed. For manual rollback, we need to define the operation in rollback tag. That rollback can be performed by maven command using till tag, date or change count (maven rollback).

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <changeSet author="admin" id="1">
        <createTable tableName="person">
            <column autoIncrement="true" name="id" type="INT">
                <constraints primaryKey="true"/>
            </column>
            <column name="name" type="VARCHAR(255)">
                <constraints nullable="false"/>
            </column>
            <column name="address" type="VARCHAR(255)"/>
        </createTable>
        <rollback>
            <dropTable tableName="person"/>
        </rollback>
    </changeSet>
</databaseChangeLog>

2.4.3 insert-person-table-changelog-2.xml

Now create second change log file insert-person-table-changelog-2.xml at shown in the path above file. This file’s changeSet will perform insert values operation for person table. You can find more database operation syntax for liquibase at this link.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <changeSet author="admin" id="2">
        <insert tableName="person">
            <column name="id" valueNumeric="1"/>
            <column name="name" value="Tom"/>
            <column name="address" value="USA"/>
        </insert>
    </changeSet>
</databaseChangeLog>

2.4.4 update-person-table-precondition-3.xml

Now create third change log file update-person-table-precondition-3.xml at shown in the path above file. In this file, we have used <preconditions> tag for defining preconditional statement. The changes will be executed in DB only when precondition will be satisfied. Here, we have given the condition for DBMS type must be h2. We can perform different conditions based on different factors like tableExist, sqlCheck, columnExist, etc (preconditions). Below changeSet will update the value in person table.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <changeSet author="admin" id="3">
        <preConditions>
            <dbms type="h2"/>
        </preConditions>
        <update tableName="person">
            <column name="address" value="India"/>
            <where>name = 'Tom'</where>
        </update>
    </changeSet>
</databaseChangeLog>

2.5 Output

Run mvn spring-boot run command and run spring boot application. Now, open http://localhost:8080/h2-console/  url in the browser. Login with database properties configured in application.properties file. Write SELECT * FROM PERSON  in textarea and click on Run. Your three database changes(create table, insert into table and update table with precondition) has been reflected in the output. You can also perform one by one changeSet and check the output.

Output in H2 Database

Spring Boot Liquibase Example – Database

3. Conclusion

In this tutorial, we learned how to configure and quick start Liquibase with Spring Boot. Spring Boot with Liquibase makes schema migration job easy without much more configuration. When database change management needs to be in vendor-independent databases, Liquibase would be the better choice.

Important properties related to Liquibase and Spring application

We can write following properties in application.properties file for more specific configurations – References

spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.yaml # Change log configuration path.
spring.liquibase.check-change-log-location=true # Whether to check that the change log location exists.
spring.liquibase.contexts= # Comma-separated list of runtime contexts to use.
spring.liquibase.database-change-log-lock-table=DATABASECHANGELOGLOCK # Name of table to use for tracking concurrent Liquibase usage.
spring.liquibase.database-change-log-table=DATABASECHANGELOG # Name of table to use for tracking change history.
spring.liquibase.default-schema= # Default database schema.
spring.liquibase.drop-first=false # Whether to first drop the database schema.
spring.liquibase.enabled=true # Whether to enable Liquibase support.
spring.liquibase.labels= # Comma-separated list of runtime labels to use.
spring.liquibase.liquibase-schema= # Schema to use for Liquibase objects.
spring.liquibase.liquibase-tablespace= # Tablespace to use for Liquibase objects.
spring.liquibase.parameters.*= # Change log parameters.
spring.liquibase.password= # Login password of the database to migrate.
spring.liquibase.rollback-file= # File to which rollback SQL is written when an update is performed.
spring.liquibase.test-rollback-on-update=false # Whether rollback should be tested before update is performed.
spring.liquibase.url= # JDBC URL of the database to migrate. If not set, the primary configured data source is used.
spring.liquibase.user= # Login user of the database to migrate.

4. References

5. Source Code

spring-boot-liquibase-example (20 KB)

Was this post helpful?
Let us know, if you liked the post. Only in this way, we can improve us.
Yes
No

Leave a Reply

Your email address will not be published. Required fields are marked *