Liquibase

Introduction

Liquibase is an open-source database-independent library for tracking, managing and applying database schema changes. It is intended to allow easier tracking of database changes.

As of Liquibase 3.8.x, it does not support H2 compatibility mode.

Therefore, do not use 'MODE' in the JDBC datasource URL. E.g: The following will not work as expected:

jdbc:h2:mem:test_db;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE

Subpages highlighted

https://sites.google.com/site/pawneecity/liquibase/samples-liquibase

https://sites.google.com/site/pawneecity/liquibase/spring-data-liquibase


Reference

H2 Keywords / Reserved Words

http://www.h2database.com/html/advanced.html#keywords


Data types

Liquibase types > https://docs.liquibase.com/change-types/nested-tags/column.html

Liquibase type classes > https://github.com/liquibase/liquibase/tree/master/liquibase-core/src/main/java/liquibase/datatype/core

JDK 11 types > https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/Types.html


To help make scripts database-independent, the following generic data types will be converted to the correct database implementation:

Also, specifying a java.sql.Types.* type will be converted to the correct type as well. Examples:


Notes:

See also: https://stackoverflow.com/a/4849030/1323562


Sample configuration

In this sample, we'll create the configuration needed in an Spring Boot project with Maven and a PostgreSQL database.

The following sections assume the application is already using the database connection via Sprint Boot configuration [src/main/resources/application.properties].

Maven pom.xml

In project.properties, declare the Liquibase version to be used

<liquibase.version>3.5.5</liquibase.version>

In section project.dependencies, add the Liquibase dependency

        <dependency>

            <groupId>org.liquibase</groupId>

            <artifactId>liquibase-core</artifactId>

            <version>${liquibase.version}</version>

        </dependency>

        <!-- Liquibase SessionLock for 4.x and 3.7.x (remove once it's supported by core)-->

        <dependency>

          <groupId>com.github.blagerweij</groupId>

          <artifactId>liquibase-sessionlock</artifactId>

          <version>1.6.2</version>

        </dependency>

(optional) In section project.build.plugins, the Liquibase plugin makes easy to generate database changes files

        <plugin>

                <groupId>org.liquibase</groupId>

                <artifactId>liquibase-maven-plugin</artifactId>

                <version>${liquibase.version}</version>

                <configuration>

                    <!-- By default, keep skip=true unless you need to run it manually in your development box with your own database -->

                    <skip>true</skip>

                    <outputChangeLogFile>src/main/resources/db/changelog/changes/db.change-GENERATED.yaml</outputChangeLogFile>

                    <!-- if needed, update connection values to your local development DB (this is not TEST, PRE nor PRO) -->

                    <url>jdbc:postgresql://127.0.0.1:5432/my_db</url>

                    <username>postgres</username>

                    <password>postgres</password>

                </configuration>      

        </plugin>

Generate the initial change

The Liquibase dependency looks for a master yaml file named "db.changelog-master.yaml" (at least in Spring Boot) and located in directory:

src/main/resources/db/changelog/

In this master file, let's only indicate that Liquibase must process all changes in files located in subdirectory 'changes".

db.changelog-master.xml

Note: Verified working fine with docker since Liquibase 4.0.0

<?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"  

  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">  

    <includeAll  path="db/changes/"/>  

</databaseChangeLog>

db.changelog-master.yaml

Remark: It stopped working with docker since Liquibase 4.0.0 (use the .xml alternative instead)

databaseChangeLog:

- includeAll:

    path: changes

    relativeToChangelogFile: true

And a sample file inside the 'changes' subdirectory.

db.change-001.yaml

databaseChangeLog:

- changeSet:

    id: 1

    author: baromojm (generated)

    changes:

    - createTable:

        columns:

        - column:

            autoIncrement: true

            constraints:

              primaryKey: true

              primaryKeyName: applicant_pkey

            name: id

            type: BIGSERIAL

        - column:

            name: email

            type: VARCHAR(255)

        - column:

            name: name

            type: VARCHAR(255)

        - column:

            name: phone_number

            type: VARCHAR(255)

        tableName: applicant

For generating the initial file for the 'changes' subdirectory, the easiest way seems to be executing the Liquibase plugin we've previously configured in pom.xml

mvn liquibase:generateChangeLog

Note: You'll need to rename this file and edit it to suit your specific needs.

         The idea is to create a new file in 'changes' with the differences from previous version every new release.

Keywords / Reserved Words

There is a list of keywords that can't be used as identifiers (table names, column names and so on), unless they are quoted (surrounded with double quotes).


Sample at an JPA entity:

  /** varchar(128) */

  @Column(name = "\"key\"") //'key' and 'value' are H2 keywords

  @Id

  private String key;


  /** varchar */

  @Column(name = "\"value\"") //'key' and 'value' are H2 keywords

  @Nullable

  private String value;


Troubleshooting

liquibase.lockservice : Waiting for changelog lock....

Reference > https://docs.liquibase.com/concepts/tracking-tables/databasechangeloglock-table.html

Unlock and restart the instance:

UPDATE DATABASECHANGELOGLOCK SET LOCKED=0