top of page

Streamlining Your Database Deployments with Liquibase and SpringBoot App

  • pranaypourkar
  • May 11, 2023
  • 3 min read

Updated: Jun 3, 2023


Liquibase is a powerful tool that provides a declarative way to manage database schema changes. With Liquibase, schema changes can be defined in a change log file, which can be versioned and tracked just like the application code. This makes it easy to manage database schema changes across different environments, such as development, staging, and production.


Spring Boot has built-in support for Liquibase, which means Liquibase can easily integrate into the Spring Boot application by adding the liquibase-core dependency to the project's Maven or Gradle build file, and configuring it with the necessary properties, such as the JDBC URL, username, and password.


To use Liquibase in a Spring Boot application, create a Liquibase change log file, which defines the changes to be applied to the database schema. It can be in YAML or XML or any other format which is supported, and can include a series of change sets that define the individual changes to be made to the schema.


Overall, using Liquibase as part of a Spring Boot project can help you manage database schema changes more effectively and maintain the consistency of your database schema across different environments.


Before we proceed to some coding, let's understand something about Init Container and Main Container wrt liquibase.


Init Container: An init container is a separate container that runs and completes before the main application container starts. It is primarily used for performing initialization tasks or pre-requisites required by the main container. In the context of Liquibase, an init container can be used to apply database schema changes or migrations before the main application container starts. This ensures that the database is properly prepared before the application attempts to connect to it. Liquibase can be executed as part of the init container, allowing you to manage database changes as a separate initialization step. In case of any issues with init container, main container won't be starting.


Main Container: The main container refers to the primary application container that runs the actual application logic. In the case of a Spring Boot application, the main container would be responsible for running the Spring Boot application itself including the liquibase changes.


The separation of Liquibase execution into an init container allows for better control over the database initialization process and ensures that the database schema changes are applied before the application starts. This approach helps to maintain consistency and reduces the risk of the application encountering issues due to incompatible database schema versions.



Let's get started with some hands-on.

Firstly, we will need mysql instance up and running. We will use docker-compose method to bring mysql.

docker-compose.yaml

version: "3.9"
# https://docs.docker.com/compose/compose-file/

services:
  db-mysql:
    container_name: db-mysql
    image: mysql:8.0.29
    ports:- "3306:3306"
    environment:MYSQL_ROOT_PASSWORD: root
    volumes:- mysql-data:/var/lib/mysql

volumes:
  mysql-data:
    driver: local

networks:default:
    name: company_default

docker-compose up db-mysql
ree

We will create liquibase-example-service spring boot project.

Add the following dependencies to the pom.xml file

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>

Create the main application.java class

package com.company.project;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.SpringApplication;

@SpringBootApplication
public class Application {
    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Add the required properties in application.yaml file

server:
  port: 4040
  
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/liquibase-example-schema/liquibase-example-schema?createDatabaseIfNotExist=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  liquibase:
    enabled: true
    change-log: db/changeLog-master.yaml
    
logging:
  level:
    liquibase: DEBUG

Now, let's create changelog files. We will create master changelog file and it will have reference to separate changelog files.


ree

changeLog-master.yaml

databaseChangeLog:
- includeAll:
    path: tables-setup-0_1
    relativeToChangelogFile: true

add-table-books-04052023.yaml

databaseChangeLog:
  - changeSet:
      id: 2
      author: pranay.pourkar@test.com
      labels: books
      context: books
      comment: This is the table to hold books data
      changes:
        - createTable:
            tableName: books
            columns:
              - column:
                  name: id
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: name
                  type: varchar(50)
                  constraints:
                    nullable: false

# Add a version attribute here
version: 1.0.0

add-table-users-03052023.yaml

databaseChangeLog:
  - changeSet:
      id:  1
      author: pranay.pourkar@test.com
      labels: users
      context: users
      comment: This is the table to hold users data
      changes:
        - createTable:
            tableName:  users
            columns:
              - column:
                  name:  id
                  type:  int
                  autoIncrement:  true
                  constraints:
                    primaryKey:  true
                    nullable:  false
              - column:
                  name:  name
                  type:  varchar(50)
                  constraints:
                    nullable:  false
              - column:
                  name:  age
                  type:  int
                  constraints:
                    nullable:  false
              - column:
                  name:  contact
                  type:  int
                  constraints:
                    nullable:  false
              - column:
                  name:  address
                  type:  varchar(100)
                  constraints:
                    nullable:  false

# Add a version attribute here
version: 1.0.0

update-table-users-05052023.yaml

databaseChangeLog:
  - changeSet:
      id: 3
      author: pranay.pourkar@test.com
      labels: books
      context: books
      comment: Adding author column to the books table
      changes:
        - addColumn:
            tableName: books
            columns:
              - column:
                  name: author
                  type: varchar(50)

Overall, the folder structure will look like below

ree

Build the project with below maven command and run the application
mvn clean install
ree

mvn spring-boot:run
ree
ree
From the above logs, we can see that liquibase has applied the database changes and let's verify from the MySQl Workbench as well.
ree

Files are attached for the reference below.



Thank you for taking the time to read this post. I hope that you found it informative and useful in your own development work.

Comments


bottom of page