Using Liquibase

Liquibase 是用于数据库模式更改管理的开源工具。 Quarkus 提供了一流的支持来使用 Liquibase,本指南将对此进行说明。

Solution

我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。

克隆 Git 存储库: git clone $${quickstarts-base-url}.git,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。

解决方案位于 liquibase-quickstart directory

Setting up support for Liquibase

若要开始对您的项目使用 Liquibase,您只需:

  • 将您的 changeLog 添加到 src/main/resources/db/changeLog.xml 文件中,正如您通常使用 Liquibase 所做的一样

  • 激活 migrate-at-start 选项以自动迁移模式或注入 Liquibase 对象并按您通常的方式运行迁移。

在您的 pom.xml 中添加以下依赖项:

  • the Liquibase extension

  • 您的 JDBC 驱动程序扩展 (quarkus-jdbc-postgresqlquarkus-jdbc-h2quarkus-jdbc-mariadb、……)

pom.xml
<!-- Liquibase specific dependencies -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-liquibase</artifactId>
</dependency>

<!-- JDBC driver dependencies -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
build.gradle
// Liquibase specific dependencies
implementation("io.quarkus:quarkus-liquibase")

// JDBC driver dependencies
implementation("io.quarkus:quarkus-jdbc-postgresql")

Liquibase 支持依赖于 Quarkus 数据源配置。它可以为默认数据源以及每个 named datasource 自定义。首先,您需要将数据源配置添加到 application.properties 文件中,以允许 Liquibase 管理模式。

以下是 application.properties 文件的一个示例:

# configure your datasource
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=sarah
quarkus.datasource.password=connor
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase

# Liquibase minimal config properties
quarkus.liquibase.migrate-at-start=true

# Liquibase optional config properties
# quarkus.liquibase.change-log=db/changeLog.xml
# quarkus.liquibase.validate-on-migrate=true
# quarkus.liquibase.clean-at-start=false
# quarkus.liquibase.database-change-log-lock-table-name=DATABASECHANGELOGLOCK
# quarkus.liquibase.database-change-log-table-name=DATABASECHANGELOG
# quarkus.liquibase.contexts=Context1,Context2
# quarkus.liquibase.labels=Label1,Label2
# quarkus.liquibase.default-catalog-name=DefaultCatalog
# quarkus.liquibase.default-schema-name=DefaultSchema
# quarkus.liquibase.liquibase-catalog-name=liquibaseCatalog
# quarkus.liquibase.liquibase-schema-name=liquibaseSchema
# quarkus.liquibase.liquibase-tablespace-name=liquibaseSpace

按照 Liquibase 命名约定向默认文件夹中添加 changeLog 文件: `src/main/resources/db/changeLog.xml`yaml、json、xml 和 sql changeLog 文件格式也受支持。

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext
    https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
    http://www.liquibase.org/xml/ns/dbchangelog
    https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">

    <changeSet author="quarkus" id="1">
        <createTable tableName="quarkus">
            <column name="ID" type="VARCHAR(255)">
                <constraints nullable="false"/>
            </column>
            <column name="NAME" type="VARCHAR(255)"/>
        </createTable>
    </changeSet>
</databaseChangeLog>

你现在可以启动你的应用程序,Quarkus 会根据你的配置运行 Liquibase 更新方法:

import io.quarkus.liquibase.LiquibaseFactory; 1

@ApplicationScoped
public class MigrationService {
    // You can Inject the object if you want to use it manually
    @Inject
    LiquibaseFactory liquibaseFactory; 2

    public void checkMigration() {
        // Get the list of liquibase change set statuses
        try (Liquibase liquibase = liquibaseFactory.createLiquibase()) {
            List<ChangeSetStatus> status = liquibase.getChangeSetStatuses(liquibaseFactory.createContexts(), liquibaseFactory.createLabels());
        }
    }
}
1 Quarkus 扩展提供一个工厂来初始化 Liquibase 实例
2 如果你想直接使用 Liquibase 方法,请注入 Quarkus Liquibase 工厂

Multiple datasources

Liquibase 可以为多个数据源进行配置。Liquibase 属性的添加前缀方式与命名数据源完全相同,例如:

quarkus.datasource.db-kind=h2
quarkus.datasource.username=username-default
quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:default
quarkus.datasource.jdbc.max-size=13

quarkus.datasource.users.db-kind=h2
quarkus.datasource.users.username=username1
quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/mem:users
quarkus.datasource.users.jdbc.max-size=11

quarkus.datasource.inventory.db-kind=h2
quarkus.datasource.inventory.username=username2
quarkus.datasource.inventory.jdbc.url=jdbc:h2:tcp://localhost/mem:inventory
quarkus.datasource.inventory.jdbc.max-size=12

# Liquibase configuration for the default datasource
quarkus.liquibase.schemas=DEFAULT_TEST_SCHEMA
quarkus.liquibase.change-log=db/changeLog.xml
quarkus.liquibase.migrate-at-start=true

# Liquibase configuration for the "users" datasource
quarkus.liquibase.users.schemas=USERS_TEST_SCHEMA
quarkus.liquibase.users.change-log=db/users.xml
quarkus.liquibase.users.migrate-at-start=true

# Liquibase configuration for the "inventory" datasource
quarkus.liquibase.inventory.schemas=INVENTORY_TEST_SCHEMA
quarkus.liquibase.inventory.change-log=db/inventory.xml
quarkus.liquibase.inventory.migrate-at-start=true

请注意,键中有一个额外的位。语法如下:.quarkus.liquibase.[optional name.][datasource property]

如果没有配置,Liquibase 将使用默认设置针对每个数据源进行设置。

Using the Liquibase object

如果你有兴趣直接使用 Liquibase 对象,你可以按如下方式注入它:

如果你启用了 quarkus.liquibase.migrate-at-start 属性,那么当你在使用 Liquibase 实例时,Quarkus 已经运行了迁移操作。

import io.quarkus.liquibase.LiquibaseFactory;

@ApplicationScoped
public class MigrationService {
    // You can Inject the object if you want to use it manually
    @Inject
    LiquibaseFactory liquibaseFactory; 1

    @Inject
    @LiquibaseDataSource("inventory") 2
    LiquibaseFactory liquibaseFactoryForInventory;

    @Inject
    @Named("liquibase_users") 3
    LiquibaseFactory liquibaseFactoryForUsers;

    public void checkMigration() {
        // Use the liquibase instance manually
        try (Liquibase liquibase = liquibaseFactory.createLiquibase()) {
            liquibase.dropAll(); 4
            liquibase.validate();
            liquibase.update(liquibaseFactory.createContexts(), liquibaseFactory.createLabels());
            // Get the list of liquibase change set statuses
            List<ChangeSetStatus> status = liquibase.getChangeSetStatuses(liquibaseFactory.createContexts(), liquibaseFactory.createLabels()); 5
        }
    }
}
1 Inject the LiquibaseFactory object
2 使用 Quarkus LiquibaseDataSource 限定符为已命名的数据源注入 Liquibase
3 为已命名的数据源注入 Liquibase
4 直接使用 Liquibase 实例
5 已应用或未应用的 Liquibase ChangeSets 列表

Liquibase on Kubernetes

有时,最好不要在每次应用程序启动时执行 Liquibase 初始化。一个这样的例子是在 Kubernetes 上部署,在 Kubernetes 上每个副本执行 Liquibase 没有意义。相反,最好执行它一次,然后在没有 Liquibase 的情况下启动实际应用程序。为了支持这种用例,当为 Kubernetes 生成清单时,生成的清单包含 Liquibase 的 Kubernetes 初始化 JobJob 执行初始化,实际 Pod 将在 Job 成功完成后启动。

Disabling

此功能默认启用,可以使用以下内容进行全局禁用:

quarkus.kubernetes.init-task-defaults.enabled=false

或在 OpenShift 上:

quarkus.openshift.init-task-defaults.enabled=false

Using a custom image that controls waiting for the Job

若要更改默认`groundnuty/k8s-wait-for:no-root-v1.7` 的 wait-for 图像,可以使用:

quarkus.kubernetes.init-task-defaults.wait-for-container.image=my/wait-for-image:1.0

或在 OpenShift 上:

quarkus.openshift.init-task-defaults.wait-for-container.image=my/wait-for-image:1.0

Note: 在此上下文中,全局意味着 for all extensions that support init task externalization.

Configuration Reference

Unresolved include directive in modules/ROOT/pages/liquibase.adoc - include::../../../target/quarkus-generated-doc/config/quarkus-liquibase.adoc[]