Micronaut Liquibase

Integration between Micronaut and Liquibase

Version:

1 Introduction

To use the Micronaut’s integration with Liquibase you must have the micronaut-liquibase dependency on your classpath:

implementation("io.micronaut.liquibase:micronaut-liquibase")
<dependency>
    <groupId>io.micronaut.liquibase</groupId>
    <artifactId>micronaut-liquibase</artifactId>
</dependency>

2 What's New

This section will outline any breaking changes between major or milestone releases as well as detail any new features that have been added.

2.0.0.M1

  • Upgrade to Micronaut 2.0.0.M3.

  • Rename package io.micronaut.configuration.dbmigration.liquibase to io.micronaut.liquibase.

1.3.0

  • Fix issue with Micronaut Data #441.

  • Upgrade to Micronaut 1.3.3.

1.2.0

  • Support for GORM data sources has been added. See the documentation for more information.

1.1.0

  • Upgrade to Micronaut 1.1.4.

  • Stop the application when there is an error applying a migration.

1.0.0

  • Underlying implementation has been changed to run the migrations as soon as possible. If you are not extending or overriding the API, there are no functional changes to note.

1.0.0.RC1

  • First public release.

3 Configuration

You can define liquibase configuration for each datasource. The following example demonstrates using it:

src/main/resources/application.yml
datasources:
    default: (3)
        url: 'jdbc:h2:mem:liquibaseDisabledDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE'
        username: 'sa'
        password: ''
        driverClassName: 'org.h2.Driver'
jpa:
    default: (3)
        packages-to-scan:
            - 'example.micronaut'
        properties:
            hibernate:
                hbm2ddl:
                    auto: none (1)
                show_sql: true
liquibase:
    datasources: (2)
        default: (3)
            change-log: 'classpath:db/liquibase-changelog.xml' (4)
1 Disable schema DDL creation.
2 Define all liquibase configuration under key liquibase.datasources.
3 Configure liquibase configuration for default data source.
4 Root changelog under src/main/resources/db/liquibase-changelog.xml.

Often, you will have a root changelog:

resources/db/liquibase-changelog.xml
<?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.1.xsd">
  <include file="changelog/01-create-books-schema.xml" relativeToChangelogFile="true"/>
  <include file="changelog/02-insert-data-books.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

which imports changelogs which you keep generating as your app evolves:

resources/db/changelog/01-create-books-schema.xml
<?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.1.xsd">
  <changeSet id="01" author="sdelamo">
    <createTable tableName="books"
      remarks="A table to contain all books">
      <column name="id" type="int">
        <constraints nullable="false" unique="true" primaryKey="true"/>
      </column>
      <column name="name" type="varchar(255)">
        <constraints nullable="false" unique="true"/>
      </column>
    </createTable>
  </changeSet>
</databaseChangeLog>
Liquibase migrations are executed when datasources are created. Because Micronaut beans are, by default, created lazily, if you do not inject a Datasource somewhere, then migrations are not executed. This may be the case when you create a command in a separate module just to run migrations, e.g. using Micronaut support for picocli. In this case it is enough to inject a Datasource in anyone of your singletons and migrations will be executed.

There are several options available for configuration:

🔗
Table 1. Configuration Properties for LiquibaseConfigurationProperties
Property Type Description

liquibase.datasources.*.async

boolean

Whether liquibase operations should be run asynchronously.

liquibase.datasources.*.enabled

boolean

Sets whether this liquibase configuration is enabled. Default value (true).

liquibase.datasources.*.change-log

java.lang.String

Change log configuration path.

liquibase.datasources.*.default-schema

java.lang.String

Default database schema.

liquibase.datasources.*.liquibase-schema

java.lang.String

Schema to use for Liquibase objects.

liquibase.datasources.*.drop-first

boolean

Whether to first drop the database schema. Default value (false).

liquibase.datasources.*.liquibase-tablespace

java.lang.String

Tablespace to use for Liquibase objects.

liquibase.datasources.*.database-change-log-table

java.lang.String

Name of table to use for tracking change history.

liquibase.datasources.*.database-change-log-lock-table

java.lang.String

Name of table to use for tracking concurrent Liquibase usage.

liquibase.datasources.*.tag

java.lang.String

a tag.

liquibase.datasources.*.contexts

java.lang.String

Comma-separated list of runtime contexts to use.

liquibase.datasources.*.labels

java.lang.String

Comma-separated list of runtime labels to use.

liquibase.datasources.*.test-rollback-on-update

boolean

Whether rollback should be tested before update is performed. Default value (false).

liquibase.datasources.*.ignore-classpath-prefix

boolean

Ignores classpath prefix during changeset comparison. Default value (true).

liquibase.datasources.*.rollback-file-path

java.lang.String

Path to file to which rollback SQL is written when an update is performed.

liquibase.datasources.*.parameters

java.util.Map

Change log parameters.

4 GORM Support

There is also support for running Liquibase migrations when using GORM.

1.- Add the dependency:

implementation("io.micronaut.configuration:micronaut-hibernate-gorm")
<dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-hibernate-gorm</artifactId>
</dependency>

2.- You also need at least one class annotated with @grails.gorm.annotation.Entity to trigger the migrations.

src/main/groovy/example/Book.groovy
package example

import grails.gorm.annotation.Entity

import io.micronaut.context.annotation.Requires

@Entity
class Book {
    String name
}

3.- Then it is necessary to configure GORM datasource:

src/main/resources/application.yml
dataSource: (1)
  pooled: true
  jmxExport: true
  dbCreate: none (2)
  url: 'jdbc:h2:mem:GORMDb'
  driverClassName: org.h2.Driver
  username: sa
  password: ''

liquibase:
  datasources: (3)
    default: (4)
      change-log: classpath:db/liquibase-changelog.xml (5)
1 Definition of the first data source in GORM. The name it’s default and it can’t be changed.
2 Disable schema DDL creation.
3 Define liquibase configuration under liquibase.datasources key.
4 Define liquibase configuration for the default datasource.
5 The migration file path is src/main/resources/db/liquibase-changelog.xml.

Multiple Data sources

It is also possible to configure Liquibase migrations with multiple data sources when using GORM:

src/main/resources/application.yml
dataSource: (1)
  pooled: true
  jmxExport: true
  dbCreate: none
  url: 'jdbc:h2:mem:liquibaseGORMDb'
  driverClassName: org.h2.Driver
  username: sa
  password: ''

dataSources:
  books: (2)
    pooled: true
    jmxExport: true
    dbCreate: none
    url: 'jdbc:h2:mem:liquibaseBooksDb'
    driverClassName: org.h2.Driver
    username: sa
    password: ''

liquibase:
  datasources:
    default: (3)
      change-log: classpath:db/liquibase-changelog.xml
    books: (4)
      change-log: classpath:db/liquibase-changelog.xml
1 Definition of the first data source in GORM. The name it’s default and it can’t be changed.
2 Name of the additional data source.
3 Define liquibase configuration for the default datasource.
4 Define liquibase configuration for the books datasource.
For more information about how to configure GORM, take a look at the documentation.

5 Endpoint

This configuration provides a built-in endpoint to expose all the applied migrations in /liquibase.

To enable the endpoint add the following to the configuration:

resources/application.yml
endpoints:
    liquibase:
        enabled: true (1)
        sensitive: false (2)
1 /liquibase endpoint is enabled.
2 /liquibase endpoint is open for unauthenticated access.
$ curl http://localhost:8080/liquibase

[{
    "name": "default",
    "changeSets": [{
        "author": "sdelamo",
        "changeLog": "classpath:db/changelog/01-create-books-and-author-schema.xml",
        "comments": "",
        "contexts": [],
        "dateExecuted": "2018-10-29T16:33:05Z",
        "deploymentId": "0830784929",
        "description": "createTable tableName=books; createTable tableName=authors; addForeignKeyConstraint baseTableName=books, constraintName=author_fk, referencedTableName=authors",
        "execType": "EXECUTED",
        "id": "01",
        "labels": [],
        "checksum": "8:140eb966bb6a14bccade2c2d9133b7d3",
        "orderExecuted": 1,
        "tag": "tag1"
    }, {
        "author": "sdelamo",
        "changeLog": "classpath:db/changelog/02-insert-data-authors.xml",
        "comments": "Inserting Authors",
        "contexts": [],
        "dateExecuted": "2018-10-29T16:33:05Z",
        "deploymentId": "0830784929",
        "description": "insert tableName=authors; insert tableName=authors; insert tableName=authors; insert tableName=authors; insert tableName=authors",
        "execType": "EXECUTED",
        "id": "02",
        "labels": [],
        "checksum": "8:6204c525ce5c1c55f064888d078b8f05",
        "orderExecuted": 2,
        "tag": null
    }]
}]
See the section on Built-in endpoints in the user guide for more information.