implementation("io.micronaut.liquibase:micronaut-liquibase")
Table of Contents
Micronaut Liquibase
Integration between Micronaut and Liquibase
Version:
1 Introduction
The Micronaut Liquibase integration runs Liquibase changelogs. It does not create changelogs.
To use the Micronaut’s integration with Liquibase you must have the micronaut-liquibase
dependency on your classpath:
<dependency>
<groupId>io.micronaut.liquibase</groupId>
<artifactId>micronaut-liquibase</artifactId>
</dependency>
2 Release History
For this project, you can find a list of releases (with release notes) here:
3 Configuration
You can define liquibase configuration for each datasource. The following example demonstrates using it:
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:
<?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:
<?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:
Property | Type | Description |
---|---|---|
|
boolean |
Whether liquibase operations should be run asynchronously. |
|
boolean |
Sets whether this liquibase configuration is enabled. Default value (true). |
|
java.lang.String |
Change log configuration path. |
|
java.lang.String |
Default database schema. |
|
java.lang.String |
Schema to use for Liquibase objects. |
|
boolean |
Whether to first drop the database schema. Default value (false). |
|
java.lang.String |
Tablespace to use for Liquibase objects. |
|
java.lang.String |
Name of table to use for tracking change history. |
|
java.lang.String |
Name of table to use for tracking concurrent Liquibase usage. |
|
java.lang.String |
a tag. |
|
java.lang.String |
Comma-separated list of runtime contexts to use. |
|
java.lang.String |
Comma-separated list of runtime labels to use. |
|
boolean |
Whether rollback should be tested before update is performed. Default value (false). |
|
java.lang.String |
Path to file to which rollback SQL is written when an update is performed. |
|
java.util.Map |
Change log parameters. |
|
boolean |
Ignores classpath prefix during changeset comparison. |
Logging
Liquibase 4.0 has changed how logging is done and now it is based on Java Util Logging (JUL). This means that without doing anything the log format won’t be the usual in Micronaut:
16:39:58.744 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
16:39:58.945 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
Nov 10, 2020 4:39:59 PM liquibase.lockservice
INFO: Successfully acquired change log lock
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: Creating database history table with name: PUBLIC.DATABASECHANGELOG
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: Reading from PUBLIC.DATABASECHANGELOG
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: Table users created
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: ChangeSet db/changelog/01-create-users-table.xml::01::ilopmar ran successfully in 10ms
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: New row inserted into users
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: New row inserted into users
Nov 10, 2020 4:39:59 PM liquibase.changelog
INFO: ChangeSet db/changelog/02-insert-users-data.xml::02::ilopmar ran successfully in 4ms
Nov 10, 2020 4:39:59 PM liquibase.lockservice
INFO: Successfully released change log lock
16:40:00.277 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 2392ms. Server Running: http://localhost:8080
If you want to integrate JUL and Logback you need to do the following in your application:
-
Add the dependency:
implementation("org.slf4j:jul-to-slf4j:1.7.30")
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
-
Add the following
contextListener
to yourlogback.xml
:
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<appender ...>
...
</appender>
...
</configuration>
-
Initialize the JUL to Slf4j bridge. You can add the following to your
Application
class:
public static void main(String[] args) {
// Bridge JUL to Slf4j
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
Micronaut.run(Application.class, args);
}
With the previous configuration, starting your application again will show the logs properly:
16:47:10.868 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
16:47:11.042 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
16:47:11.344 [main] INFO liquibase.lockservice - Successfully acquired change log lock
16:47:11.744 [main] INFO liquibase.changelog - Creating database history table with name: PUBLIC.DATABASECHANGELOG
16:47:11.747 [main] INFO liquibase.changelog - Reading from PUBLIC.DATABASECHANGELOG
16:47:11.844 [main] INFO liquibase.changelog - Table users created
16:47:11.844 [main] INFO liquibase.changelog - ChangeSet db/changelog/01-create-users-table.xml::01::ilopmar ran successfully in 20ms
16:47:11.857 [main] INFO liquibase.changelog - New row inserted into users
16:47:11.858 [main] INFO liquibase.changelog - New row inserted into users
16:47:11.859 [main] INFO liquibase.changelog - ChangeSet db/changelog/02-insert-users-data.xml::02::ilopmar ran successfully in 3ms
16:47:11.861 [main] INFO liquibase.lockservice - Successfully released change log lock
16:47:12.288 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 2213ms. Server Running: http://localhost:8080
4 GORM Support
There is also support for running Liquibase migrations when using GORM.
1.- Add the dependency:
implementation("io.micronaut.groovy:micronaut-hibernate-gorm")
<dependency>
<groupId>io.micronaut.groovy</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.
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:
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:
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 GraalVM support
Micronaut Liquibase is compatible with GraalVM so it is possible to create native images and run the migrations during application startup.
Everything is handled automatically by the library so users don’t need any special configuration.
See the section on GraalVM in the user guide for more information. |
6 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:
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. |
7 Repository
You can find the source code of this project in this repository: