Getting Started with Liquibase and Spring Boot


23 Apr 2021  Sergio Martin Rubio  6 mins read.

Liquibase is a popular library for versioning and deploying database changes. This is an open source library and widely use in the Java ecosystem or as part of a Jenkins build.

Manual SQL schema updates are commonly used but they are not recommended if you want to keep track of the changes in your database. With Liquibase you can know what changes have been applied and when they were made so you could easily roll back the SQL schema to a previous state.

The Internals

Liquibase simply runs SQL commands and adds records of the changes on a table named DATABASECHANGELOG which is responsible for keeping track of all the changes on a particular database. Every time a new change is applied through Liquibase a new record is added to the DATABASECHANGELOG.

Each change log record has its own MD5 hash and they are checked against the Liquibase changeset files when loading the Liquibase configuration. If a change is made on a changeset that is already applied, Liquibase will interrupt the execution and log a validation error in order to prevent modifying the history of changes.

How to Use

We are going to use Liquibase in combination with Maven and Spring.

  1. Create a Spring Boot project at the Spring initializr site.

  2. Add the required dependencies to your pom.xml file. You will need at least three dependencies: the database connector (e.g. postgresql, mysql…), the JPA dependency and the liquibase dependency.

    <dependency>
       <groupId>org.postgresql</groupId>
       <artifactId>postgresql</artifactId>
       <scope>runtime</scope>
    </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>
    
  3. Add the database configuration to your application.properties or application.yml. e.g.:

    spring.datasource.url=jdbc:postgresql://localhost:5432/my-database
    spring.datasource.driver-class-name=org.postgresql.Driver
    spring.datasource.username=postgres
    spring.datasource.password=postgres
    
  4. Create a master change set file (db.changelog-master.yaml) in the default Liquibase changelog folder (src/main/resources/db/changelog).

    databaseChangeLog:
      - include:
          file: db/changelog/changeset/document-table.yaml
      - include:
          file: db/changelog/changeset/person-table.yaml
    

    You can organize you change sets in different files, for example, one for each SQL table.

    e.g. src/main/resources/db/changelog/changeset/document-table.yaml:

    databaseChangeLog:
      - changeSet:
          id: craete-document-table
          author: Sergio Martin Rubio
          changes:
            - createTable:
                tableName: document
                columns:
                  - column:
                      name: customer_id
                      type: varchar(255)
                      constraints:
                        primaryKey: true
                        nullable: false
                  - column:
                      name: document_url
                      type: varchar(255)
                      constraints:
                        nullable: false
    
  5. Get your database up and running. For example you can use Docker to spin up a PostgreSQL database:

    version: '3'
    services:
      postgres:
        container_name: postgres
        image: "postgres:latest"
        ports:
          - "5432:5432"
        environment:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: my-database
    
  6. Run your Spring Boot application from the command line with ./mvnw spring-boot:run

Liquibase also provides an API to configure things like the location of the master changeset file (spring.liquibase.change-log). A full list of all the properties can be found on the Spring documentation.

Liquibase Directives

Some of the most common Liquibase directives are:

  • Create a table:

    - changeSet:
        id: craete-person-table
        author: Sergio Martin Rubio
        changes:
          - createTable:
              tableName: person
              columns:
                - column:
                    name: id
                    type: varchar(255)
                    constraints:
                      primaryKey: true
                      nullable: false
                - column:
                    name: customer_id
                    type: varchar(255)
                    constraints:
                      nullable: false
                      foreignKeyName: fk_person_document
                      references: document(customer_id)
                - column:
                    name: last_name
                    type: varchar(255)
                    constraints:
                      nullable: false
                - column:
                    name: first_name
                    type: varchar(255)
                    constraints:
                      nullable: true
                - column:
                    name: aliases
                    type: varchar(255)
                    constraints:
                      nullable: true
                - column:
                    name: category
                    type: varchar(255)
                    constraints:
                      nullable: true
                - column:
                    name: position
                    type: varchar(255)
                    constraints:
                      nullable: true
                - column:
                    name: keywords
                    type: varchar(255)
                    constraints:
                      nullable: true
                - column:
                    name: entered
                    type: date
                    constraints:
                      nullable: true
                - column:
                    name: updated
                    type: date
                    constraints:
                      nullable: true
    
  • Modify a column:

    - changeSet:
        id: change-aliases-column-type
        author: Sergio Martin Rubio
        changes:
          - modifyDataType:
              columnName: aliases
              newDataType: clob
              tableName: person
    
  • Add primary key:

    - changeSet:
        id: add-primary-key
        author: Sergio Martin Rubio
        changes:
          - addPrimaryKey:
              columnNames: id
              tableName: person
    
  • Drop primary key:

    - changeSet:
        id: drop-primary-key
        author: Sergio Martin Rubio
        changes:
          - dropPrimaryKey:
              dropIndex: true
              tableName: person
    
  • Add foreign key:

    - changeSet:
        id: add-foreign-key
        author: Sergio Martin Rubio
        changes:
          - dropForeignKeyConstraint:
            baseColumnNames: customer_id
            baseTableName: person
            constraintName: fk_person_document
            referencedColumnNames: customer_id
            referencedTableName: customer
    
  • Drop foreign key:

    - changeSet:
        id: drop-foreign-key
        author: Sergio Martin Rubio
        changes:
          - dropForeignKeyConstraint:
              baseTableName: person
              constraintName: fk_person_document
    

A full list of changes that can be applied can be found on the official Liquibase documentation.

Examples