The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

Hibernate ORMとJakarta Persistenceの使用

Hibernate ORMは、Jakarta Persistence(旧称JPA)のデファクトスタンダード実装であり、Object Relational Mapperの完全な実装を提供します。 Quarkusで見事に機能します。

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリケーションを作成することを推奨します。 ただし、完成した例にそのまま進むこともできます。

Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git, or download an archive.

解決策は hibernate-orm-quickstart ディレクトリー にあります。

Hibernate ORMのセットアップと設定

QuarkusでHibernate ORMを使用する場合は、 設定の為に persistence.xml リソースは必要ありません。

このような古典的な設定ファイルを使用することは選択しとしてありますが、特定の高度なニーズがない限り不要です。 そのため、まずはHibernate ORMを persistence.xml リソース無しで設定できることをみていきましょう。

Quarkusでは、以下の点のみを実行します。

  • application.properties に設定を追加します。

  • エンティティーに @Entity やその他のマッピングアノテーションを通常どおりにアノテーションします。

その他の設定の必要性は自動化されています。Quarkusは、いくつかの定見に基づいた選択と経験に基づいた推測を行います。

以下の依存関係をプロジェクトに追加してください:

  • Hibernate ORM エクステンション: io.quarkus:quarkus-hibernate-orm

  • JDBC ドライバーエクステンション。以下のオプションを使用できます:

例えば:

pom.xml
<!-- Hibernate ORM specific dependencies -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-hibernate-orm</artifactId>
</dependency>

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

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

@Entity で永続オブジェクトにアノテーションを付けてから、 application.properties で関連する設定プロパティーを追加します。

例: application.properties
quarkus.datasource.db-kind = postgresql (1)
quarkus.datasource.username = hibernate
quarkus.datasource.password = hibernate
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/hibernate_db

quarkus.hibernate-orm.database.generation=drop-and-create (2)
1 データソースを設定します
2 起動時にデータベースを削除して作成します (スキーマのみを更新するには update を使用します)。

これらの設定プロパティーは、通常のHibernate ORMの設定ファイルにあるものとは異なることに注意してください。 多くの場合はHibernate ORMの設定のプロパティーに対応していますが、名前が異なる場合もあり、必ずしも1対1で対応しているわけではありません。

また、Quarkusは多くのHibernate ORMの設定を自動的に設定し、多くの場合、より現代的なデフォルト値を使用します。

application.properties で設定できる項目のリストについては、Hibernate ORM configuration properties を参照してください。

Hibernate ORM エクステンションがプロジェクトの依存関係の中に入っていればQuarkus の datasource の設定に基づいて EntityManagerFactory が作成されます。

ダイアレクトはデータソースに基づいて自動的に選択および設定されます。 configure it to more precisely match your database (データベースにより正確に一致するように設定) することを推奨します。

その後、 EntityManager をうまく注入することができます。

Hibernateを使用したアプリケーションBeanの例
@ApplicationScoped
public class SantaClausService {
    @Inject
    EntityManager em; (1)

    @Transactional (2)
    public void createGift(String giftDescription) {
        Gift gift = new Gift();
        gift.setName(giftDescription);
        em.persist(gift);
    }
}
1 エンティティマネージャーを注入して楽しみます。
2 CDI Beanメソッドに @Transactional を付けると EntityManager がトランザクション境界内に入りコミット時にフラッシュします。
エンティティーの例
@Entity
public class Gift {
    private Long id;
    private String name;

    @Id
    @SequenceGenerator(name = "giftSeq", sequenceName = "gift_id_seq", allocationSize = 1, initialValue = 1)
    @GeneratedValue(generator = "giftSeq")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Hibernate ORMの起動時にSQL文をロードするには、 import.sql ファイルをresourcesディレクトリーのルートに追加します。 このスクリプトには、任意のSQL DML文を含めることができます。 各ステートメントは必ずセミコロンで終了させてください。

テストやデモ用のデータセットを用意しておくと便利です。

データベースを変更するメソッド (例: entity.persist()) をトランザクション内でラップするようにしてください。 CDI Bean メソッド @Transactional をマークすることで、それを実現出来、そのメソッドをトランザクションの境界に出来ます。REST エンドポイントコントローラーのように、 アプリケーションのエントリーポイントの境界でこれを行うことを推奨します。

Dialect

サポートされるデータベース

サポートされているデータベース では、 Hibernate ORM ダイアレクト は 明示的に設定する必要はありません。 データソースに基づいて自動的に選択されます。

デフォルトでは、データベースの最小サポートバージョンをターゲットとするようにdialectが設定されています。

Hibernate ORMがより効率的なSQLを生成し、 ワークアラウンドを回避し、より多くのデータベース機能を活用するために、 データベースバージョンを明示的に設定することができます:

明示的な db-version を持つ application.properties
quarkus.datasource.db-kind = postgresql
quarkus.datasource.db-version = 14.0 (1)
quarkus.datasource.username = hibernate
quarkus.datasource.password = hibernate
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/hibernate_db
1 データベースのバージョンを設定します。Hibernate ORM dialectはそのバージョンをターゲットにします。

原則として、ここで設定するバージョンはできるだけ高くする必要がありますが、 アプリケーションが接続するデータベースのバージョン以下である必要があります。

上述したように、このバージョンは quarkus.datasource.db-version 設定プロパティーを介して明示的に事前設定されるか、 または、Quarkus ビルドプロセスによって、データベースのサポートされている最小バージョンに暗黙的に設定されます。 Quarkus は起動時にこの事前設定されたバージョンと実際のデータベースバージョンを比較しようとします。 これにより、実際のバージョンが低い場合に起動に失敗します。

これは安全策です。設定されたバージョンよりも古いデータベースを使用すると、 Hibernate ORM が無効な SQL を生成し、実行時例外が発生する可能性があります。

データベースにアクセスできない場合は警告が記録されますが、起動は続行されます。 起動時にデータベースにアクセスできないことがわかっている場合は、 quarkus.hibernate-orm.database.version-check.enabled=false を使用して、オプションでバージョンチェックを無効化できます。

ダイアレクトが明示的に設定されている場合、バージョンチェックはデフォルトで無効化されています。 これは #42255/#43703 の回避策です。

その他のデータベース

データベースに対応する Quarkus エクステンションがない 場合、 または何らかの理由でデフォルト設定がニーズに合わない場合は、 Hibernate ORM のダイアレクト を明示的に設定する必要があります。

明示的な dialect を持つ application.properties
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = hibernate
quarkus.datasource.password = hibernate
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:26257/hibernate_db

quarkus.hibernate-orm.dialect=Cockroach (1)
1 Hibernate ORM dialectを設定します。

組み込みダイアレクトの場合、指定できる値は ダイアレクトの公式リスト にある名前のいずれかで、 Dialect の接尾辞を 除いた ものです。 たとえば、 CockroachDialect の場合は Cockroach となります。

サードパーティーのダイアレクトの場合、期待される値は完全修飾クラス名です。 たとえば com.acme.hibernate.AcmeDbDialect などです。

この場合、JDBCドライバやHibernate ORM dialectがGraalVMネイティブ実行可能ファイルでは 正しく動作しない可能性があることに留意してください。

supported databases と同様に、 Hibernate ORM を最大限に活用するために、DB バージョンを明示的に設定できます。

明示的な dialectdb-version を持つ application.properties
quarkus.datasource.db-kind = postgresql
quarkus.datasource.db-version = 22.2 (1)
quarkus.datasource.username = hibernate
quarkus.datasource.password = hibernate
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:26257/hibernate_db

quarkus.hibernate-orm.dialect=Cockroach (2)
1 データベースのバージョンを設定します。Hibernate ORM dialectはそのバージョンをターゲットにします。 ここではCockroachDBをターゲットにしているので、PostgreSQLのバージョンではなく、CockroachDBのバージョンを渡しています。
2 Hibernate ORM dialectを設定します。

データベースの切り替え

database multi-tenancy を有効にすると、 Hibernate ORM は実行時に同じ永続化ユニットに対して複数のデータソースを使用します。 デフォルトでは Quarkus はどのデータソースが使用されるかを判断できません。 そのため、Hibernate ORM で使用するダイアレクトを検出できなくなります。

このような理由から、database multi-tenancy を有効化する場合は、 実行時に使用されるデータソースの中から 1 つを Hibernate ORM の設定で明示的に 指定することを推奨します。たとえば、 quarkus.hibernate-orm.datasource=base (base はデータソースの名前) などのように指定します。

これを実行すると、Quarkus はそのデータソースからデータベースのバージョンと (可能な場合) ダイアレクトを推測します。 サポートされていないデータベースの場合は、this section で説明したように、 Hibernate ORM ダイアレクトを明示的に設定する必要がある場合があります。

Hibernate ORMの設定プロパティー

EntityManagerFactory を改良したり、Quarkusの推測を導くのに便利な様々なオプションのプロパティーがあります。

デフォルトのデータソースが設定されていれば、それ以外に必須のプロパティーはありません。

プロパティーが設定されていない場合、Quarkusは通常はHibernate ORMのセットアップに必要な値を推測し、 デフォルトのデータソースを使用するようにします。

ここに記載されている設定プロパティーでは、このようなデフォルトを上書きしたり、様々な面をカスタマイズしたり調整したりすることができます。

ビルド時に固定された設定プロパティー。その他の設定プロパティーは、すべて実行時にオーバーライド可能です。

Configuration property

デフォルト

Whether Hibernate ORM is enabled during the build.

If Hibernate ORM is disabled during the build, all processing related to Hibernate ORM will be skipped, but it will not be possible to activate Hibernate ORM at runtime: quarkus.hibernate-orm.active will default to false and setting it to true will lead to an error.

Environment variable: QUARKUS_HIBERNATE_ORM_ENABLED

Show more

boolean

true

If true, Quarkus will ignore any persistence.xml file in the classpath and rely exclusively on the Quarkus configuration.

Environment variable: QUARKUS_HIBERNATE_ORM_PERSISTENCE_XML_IGNORE

Show more

boolean

false

Whether statistics collection is enabled. If 'metrics.enabled' is true, then the default here is considered true, otherwise the default is false.

Environment variable: QUARKUS_HIBERNATE_ORM_STATISTICS

Show more

boolean

Whether session metrics should be appended into the server log for each Hibernate session. This only has effect if statistics are enabled (quarkus.hibernate-orm.statistics). The default is false (which means both statistics and log-session-metrics need to be enabled for the session metrics to appear in the log).

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_SESSION_METRICS

Show more

boolean

Whether metrics are published if a metrics extension is enabled.

Environment variable: QUARKUS_HIBERNATE_ORM_METRICS_ENABLED

Show more

boolean

false

Enable or disable access to a Hibernate ORM EntityManager/Session/StatelessSession *when no transaction is active* but a request scope is. When enabled, the corresponding sessions will be read-only. Defaults to enabled for backwards compatibility, but disabling this is recommended, to avoid inconsistent resulsts caused by queries running outside of transactions.

Environment variable: QUARKUS_HIBERNATE_ORM_REQUEST_SCOPED_ENABLED

Show more

boolean

true

quarkus.hibernate-orm."persistence-unit-name".datasource

The name of the datasource which this persistence unit uses.

If undefined, it will use the default datasource.

Environment variable: QUARKUS_HIBERNATE_ORM_DATASOURCE

Show more

string

quarkus.hibernate-orm."persistence-unit-name".packages

The packages in which the entities affected to this persistence unit are located.

Environment variable: QUARKUS_HIBERNATE_ORM_PACKAGES

Show more

list of string

quarkus.hibernate-orm."persistence-unit-name".sql-load-script

Paths to files containing the SQL statements to execute when Hibernate ORM starts.

The files are retrieved from the classpath resources, so they must be located in the resources directory (e.g. src/main/resources).

The default value for this setting differs depending on the Quarkus launch mode:

  • In dev and test modes, it defaults to import.sql. Simply add an import.sql file in the root of your resources directory and it will be picked up without having to set this property. Pass no-file to force Hibernate ORM to ignore the SQL import file.

  • In production mode, it defaults to no-file. It means Hibernate ORM won’t try to execute any SQL import file by default. Pass an explicit value to force Hibernate ORM to execute the SQL import file.

If you need different SQL statements between dev mode, test (@QuarkusTest) and in production, use Quarkus configuration profiles facility.

application.properties
%dev.quarkus.hibernate-orm.sql-load-script = import-dev.sql
%test.quarkus.hibernate-orm.sql-load-script = import-test.sql
%prod.quarkus.hibernate-orm.sql-load-script = no-file

Quarkus supports .sql file with SQL statements or comments spread over multiple lines. Each SQL statement must be terminated by a semicolon.

Environment variable: QUARKUS_HIBERNATE_ORM_SQL_LOAD_SCRIPT

Show more

list of string

import.sql in dev and test modes ; no-file otherwise

quarkus.hibernate-orm."persistence-unit-name".physical-naming-strategy

Pluggable strategy contract for applying physical naming rules for database object names. Class name of the Hibernate PhysicalNamingStrategy implementation

Environment variable: QUARKUS_HIBERNATE_ORM_PHYSICAL_NAMING_STRATEGY

Show more

string

quarkus.hibernate-orm."persistence-unit-name".implicit-naming-strategy

Pluggable strategy for applying implicit naming rules when an explicit name is not given. Class name of the Hibernate ImplicitNamingStrategy implementation

Environment variable: QUARKUS_HIBERNATE_ORM_IMPLICIT_NAMING_STRATEGY

Show more

string

quarkus.hibernate-orm."persistence-unit-name".metadata-builder-contributor

Class name of a custom org.hibernate.boot.spi.MetadataBuilderContributor implementation.

Not all customization options exposed by org.hibernate.boot.MetadataBuilder will work correctly. Stay clear of options related to classpath scanning in particular.

This setting is exposed mainly to allow registration of types, converters and SQL functions.

Environment variable: QUARKUS_HIBERNATE_ORM_METADATA_BUILDER_CONTRIBUTOR

Show more

string

quarkus.hibernate-orm."persistence-unit-name".mapping-files

XML files to configure the entity mapping, e.g. META-INF/my-orm.xml.

Defaults to META-INF/orm.xml if it exists. Pass no-file to force Hibernate ORM to ignore META-INF/orm.xml.

Environment variable: QUARKUS_HIBERNATE_ORM_MAPPING_FILES

Show more

list of string

META-INF/orm.xml if it exists; no-file otherwise

quarkus.hibernate-orm."persistence-unit-name".quote-identifiers.strategy

Identifiers can be quoted using one of the available strategies.

Set to none by default, meaning no identifiers will be quoted. If set to all, all identifiers and column definitions will be quoted. Additionally, setting it to all-except-column-definitions will skip the column definitions, which can usually be required when they exist, or else use the option only-keywords to quote only identifiers deemed SQL keywords by the Hibernate ORM dialect.

Environment variable: QUARKUS_HIBERNATE_ORM_QUOTE_IDENTIFIERS_STRATEGY

Show more

none, all, all-except-column-definitions, only-keywords

none

quarkus.hibernate-orm."persistence-unit-name".second-level-caching-enabled

The default in Quarkus is for 2nd level caching to be enabled, and a good implementation is already integrated for you.

Just cherry-pick which entities should be using the cache.

Set this to false to disable all 2nd level caches.

Environment variable: QUARKUS_HIBERNATE_ORM_SECOND_LEVEL_CACHING_ENABLED

Show more

boolean

true

quarkus.hibernate-orm."persistence-unit-name".validation.mode

Defines how the Bean Validation integration behaves.

Environment variable: QUARKUS_HIBERNATE_ORM_VALIDATION_MODE

Show more

list of auto, callback, ddl, none

auto

quarkus.hibernate-orm."persistence-unit-name".multitenant

Defines the method for multi-tenancy (DATABASE, NONE, SCHEMA). The complete list of allowed values is available in the Hibernate ORM JavaDoc. The type DISCRIMINATOR is currently not supported. The default value is NONE (no multi-tenancy).

Environment variable: QUARKUS_HIBERNATE_ORM_MULTITENANT

Show more

string

quarkus.hibernate-orm."persistence-unit-name".validate-in-dev-mode

If hibernate is not auto generating the schema, and Quarkus is running in development mode then Quarkus will attempt to validate the database after startup and print a log message if there are any problems.

Environment variable: QUARKUS_HIBERNATE_ORM_VALIDATE_IN_DEV_MODE

Show more

boolean

true

quarkus.hibernate-orm."persistence-unit-name".active

Whether this persistence unit should be active at runtime.

Note that if Hibernate ORM is disabled (i.e. quarkus.hibernate-orm.enabled is set to false), all persistence units are deactivated, and setting this property to true will fail.

Environment variable: QUARKUS_HIBERNATE_ORM_ACTIVE

Show more

boolean

'true' if Hibernate ORM is enabled; 'false' otherwise

quarkus.hibernate-orm."persistence-unit-name".unsupported-properties."full-property-key"

Properties that should be passed on directly to Hibernate ORM. Use the full configuration property key here, for instance quarkus.hibernate-orm.unsupported-properties."hibernate.order_inserts" = true.

Properties set here are completely unsupported: as Quarkus doesn’t generally know about these properties and their purpose, there is absolutely no guarantee that they will work correctly, and even if they do, that may change when upgrading to a newer version of Quarkus (even just a micro/patch version).

Consider using a supported configuration property before falling back to unsupported ones. If none exists, make sure to file a feature request so that a supported configuration property can be added to Quarkus, and more importantly so that the configuration property is tested regularly.

Environment variable: QUARKUS_HIBERNATE_ORM_UNSUPPORTED_PROPERTIES__FULL_PROPERTY_KEY_

Show more

Map<String,String>

Database related configuration

デフォルト

When set, attempts to exchange data with the database as the given version of Hibernate ORM would have, on a best-effort basis.

Please note:

  • schema validation may still fail in some cases: this attempts to make Hibernate ORM 6+ behave correctly at runtime, but it may still expect a different (but runtime-compatible) schema.

  • robust test suites are still useful and recommended: you should still check that your application behaves as intended with your legacy schema.

  • this feature is inherently unstable: some aspects of it may stop working in future versions of Quarkus, and older versions will be dropped as Hibernate ORM changes pile up and support for those older versions becomes too unreliable.

  • you should still plan a migration of your schema to a newer version of Hibernate ORM. For help with migration, refer to the Quarkus 3 migration guide from Hibernate ORM 5 to 6.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_ORM_COMPATIBILITY_VERSION

Show more

5.6, latest

latest

quarkus.hibernate-orm."persistence-unit-name".database.charset

The charset of the database.

Used for DDL generation and also for the SQL import scripts.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_CHARSET

Show more

Charset

UTF-8

quarkus.hibernate-orm."persistence-unit-name".database.generation

Select whether the database schema is generated or not. drop-and-create is awesome in development mode. This defaults to 'none', however if Dev Services is in use and no other extensions that manage the schema are present this will default to 'drop-and-create'. Accepted values: none, create, drop-and-create, drop, update, validate.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION

Show more

string

none

quarkus.hibernate-orm."persistence-unit-name".database.generation.create-schemas

If Hibernate ORM should create the schemas automatically (for databases supporting them).

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION_CREATE_SCHEMAS

Show more

boolean

false

quarkus.hibernate-orm."persistence-unit-name".database.generation.halt-on-error

Whether we should stop on the first error when applying the schema.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION_HALT_ON_ERROR

Show more

boolean

false

quarkus.hibernate-orm."persistence-unit-name".database.default-catalog

The default catalog to use for the database objects.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_DEFAULT_CATALOG

Show more

string

quarkus.hibernate-orm."persistence-unit-name".database.default-schema

The default schema to use for the database objects.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_DEFAULT_SCHEMA

Show more

string

quarkus.hibernate-orm."persistence-unit-name".database.version-check.enabled

Whether Hibernate ORM should check on startup that the version of the database matches the version configured on the dialect (either the default version, or the one set through quarkus.datasource.db-version).

This should be set to false if the database is not available on startup.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_VERSION_CHECK_ENABLED

Show more

boolean

`true if the dialect was set automatically by Quarkus, false if it was set explicitly`

Dialect related configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".dialect

Name of the Hibernate ORM dialect.

For supported databases, this property does not need to be set explicitly: it is selected automatically based on the datasource, and configured using the DB version set on the datasource to benefit from the best performance and latest features.

If your database does not have a corresponding Quarkus extension, you will need to set this property explicitly. In that case, keep in mind that the JDBC driver and Hibernate ORM dialect may not work properly in GraalVM native executables.

For built-in dialects, the expected value is one of the names in the official list of dialects, without the Dialect suffix, for example Cockroach for CockroachDialect.

For third-party dialects, the expected value is the fully-qualified class name, for example com.acme.hibernate.AcmeDbDialect.

Environment variable: QUARKUS_HIBERNATE_ORM_DIALECT

Show more

string

selected automatically for most popular databases

quarkus.hibernate-orm."persistence-unit-name".dialect.storage-engine

The storage engine to use when the dialect supports multiple storage engines.

E.g. MyISAM or InnoDB for MySQL.

Environment variable: QUARKUS_HIBERNATE_ORM_DIALECT_STORAGE_ENGINE

Show more

string

Mapping configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".mapping.timezone.default-storage

How to store timezones in the database by default for properties of type OffsetDateTime and ZonedDateTime.

This default may be overridden on a per-property basis using @TimeZoneStorage.

Properties of type OffsetTime are not affected by this setting.
default

Equivalent to native if supported, normalize-utc otherwise.

auto

Equivalent to native if supported, column otherwise.

native

Stores the timestamp and timezone in a column of type timestamp with time zone.

Only available on some databases/dialects; if not supported, an exception will be thrown during static initialization.

column

Stores the timezone in a separate column next to the timestamp column.

Use @TimeZoneColumn on the relevant entity property to customize the timezone column.

normalize-utc

Does not store the timezone, and loses timezone information upon persisting.

Instead, normalizes the value to a timestamp in the UTC timezone.

normalize

Does not store the timezone, and loses timezone information upon persisting.

Instead, normalizes the value: * upon persisting to the database, to a timestamp in the JDBC timezone set through quarkus.hibernate-orm.jdbc.timezone, or the JVM default timezone if not set. * upon reading back from the database, to the JVM default timezone.

+ Use this to get the legacy behavior of Quarkus 2 / Hibernate ORM 5 or older.

Environment variable: QUARKUS_HIBERNATE_ORM_MAPPING_TIMEZONE_DEFAULT_STORAGE

Show more

native, normalize, normalize-utc, column, auto, default

default

quarkus.hibernate-orm."persistence-unit-name".mapping.id.optimizer.default

The optimizer to apply to identifier generators whose optimizer is not configured explicitly.

Only relevant for table- and sequence-based identifier generators. Other generators, such as UUID-based generators, will ignore this setting.

The optimizer is responsible for pooling new identifier values, in order to reduce the frequency of database calls to retrieve those values and thereby improve performance.

Environment variable: QUARKUS_HIBERNATE_ORM_MAPPING_ID_OPTIMIZER_DEFAULT

Show more

pooled-loAssumes the value retrieved from the table/sequence is the lower end of the pool. Upon retrieving value N, the new pool of identifiers will go from N to N + <allocation size> - 1, inclusive., pooledAssumes the value retrieved from the table/sequence is the higher end of the pool. Upon retrieving value N, the new pool of identifiers will go from N - <allocation size> to N + <allocation size> - 1, inclusive. The first value, 1, is handled differently to avoid negative identifiers. Use this to get the legacy behavior of Quarkus 2 / Hibernate ORM 5 or older., noneNo optimizer, resulting in a database call each and every time an identifier value is needed from the generator. Not recommended in production environments\: may result in degraded performance and/or frequent gaps in identifier values.

pooled-loAssumes the value retrieved from the table/sequence is the lower end of the pool. Upon retrieving value N, the new pool of identifiers will go from N to N + <allocation size> - 1, inclusive.

Query related configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".query.query-plan-cache-max-size

The maximum size of the query plan cache. see #org.hibernate.cfg.AvailableSettings#QUERY_PLAN_CACHE_MAX_SIZE

Environment variable: QUARKUS_HIBERNATE_ORM_QUERY_QUERY_PLAN_CACHE_MAX_SIZE

Show more

int

2048

quarkus.hibernate-orm."persistence-unit-name".query.default-null-ordering

Default precedence of null values in ORDER BY clauses.

Valid values are: none, first, last.

Environment variable: QUARKUS_HIBERNATE_ORM_QUERY_DEFAULT_NULL_ORDERING

Show more

none, first, last

none

quarkus.hibernate-orm."persistence-unit-name".query.in-clause-parameter-padding

Enables IN clause parameter padding which improves statement caching.

Environment variable: QUARKUS_HIBERNATE_ORM_QUERY_IN_CLAUSE_PARAMETER_PADDING

Show more

boolean

true

JDBC related configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".jdbc.timezone

The time zone pushed to the JDBC driver. See quarkus.hibernate-orm.mapping.timezone.default-storage.

Environment variable: QUARKUS_HIBERNATE_ORM_JDBC_TIMEZONE

Show more

string

quarkus.hibernate-orm."persistence-unit-name".jdbc.statement-fetch-size

How many rows are fetched at a time by the JDBC driver.

Environment variable: QUARKUS_HIBERNATE_ORM_JDBC_STATEMENT_FETCH_SIZE

Show more

int

quarkus.hibernate-orm."persistence-unit-name".jdbc.statement-batch-size

The number of updates (inserts, updates and deletes) that are sent by the JDBC driver at one time for execution.

Environment variable: QUARKUS_HIBERNATE_ORM_JDBC_STATEMENT_BATCH_SIZE

Show more

int

Fetching logic configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".fetch.batch-size

The size of the batches used when loading entities and collections.

-1 means batch loading is disabled.

Environment variable: QUARKUS_HIBERNATE_ORM_FETCH_BATCH_SIZE

Show more

int

16

quarkus.hibernate-orm."persistence-unit-name".fetch.max-depth

The maximum depth of outer join fetch tree for single-ended associations (one-to-one, many-to-one).

A 0 disables default outer join fetching.

Environment variable: QUARKUS_HIBERNATE_ORM_FETCH_MAX_DEPTH

Show more

int

Caching configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".cache."cache".expiration.max-idle

The maximum time before an object of the cache is considered expired.

Environment variable: QUARKUS_HIBERNATE_ORM_CACHE__CACHE__EXPIRATION_MAX_IDLE

Show more

Duration 

quarkus.hibernate-orm."persistence-unit-name".cache."cache".memory.object-count

The maximum number of objects kept in memory in the cache.

Environment variable: QUARKUS_HIBERNATE_ORM_CACHE__CACHE__MEMORY_OBJECT_COUNT

Show more

Discriminator related configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".discriminator.ignore-explicit-for-joined

Existing applications rely (implicitly or explicitly) on Hibernate ignoring any DiscriminatorColumn declarations on joined inheritance hierarchies. This setting allows these applications to maintain the legacy behavior of DiscriminatorColumn annotations being ignored when paired with joined inheritance.

Environment variable: QUARKUS_HIBERNATE_ORM_DISCRIMINATOR_IGNORE_EXPLICIT_FOR_JOINED

Show more

boolean

false

Logging configuration

デフォルト

Logs SQL bind parameters.

Setting it to true is obviously not recommended in production.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_BIND_PARAMETERS

Show more

boolean

false

quarkus.hibernate-orm."persistence-unit-name".log.sql

Show SQL logs and format them nicely.

Setting it to true is obviously not recommended in production.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_SQL

Show more

boolean

false

quarkus.hibernate-orm."persistence-unit-name".log.format-sql

Format the SQL logs if SQL log is enabled

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_FORMAT_SQL

Show more

boolean

true

quarkus.hibernate-orm."persistence-unit-name".log.highlight-sql

Highlight the SQL logs if SQL log is enabled

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_HIGHLIGHT_SQL

Show more

boolean

true

quarkus.hibernate-orm."persistence-unit-name".log.jdbc-warnings

Whether JDBC warnings should be collected and logged.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_JDBC_WARNINGS

Show more

boolean

depends on dialect

quarkus.hibernate-orm."persistence-unit-name".log.queries-slower-than-ms

If set, Hibernate will log queries that took more than specified number of milliseconds to execute.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_QUERIES_SLOWER_THAN_MS

Show more

Database scripts related configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".scripts.generation

Select whether the database schema DDL files are generated or not. Accepted values: none, create, drop-and-create, drop, update, validate.

Environment variable: QUARKUS_HIBERNATE_ORM_SCRIPTS_GENERATION

Show more

string

none

quarkus.hibernate-orm."persistence-unit-name".scripts.generation.create-target

Filename or URL where the database create DDL file should be generated.

Environment variable: QUARKUS_HIBERNATE_ORM_SCRIPTS_GENERATION_CREATE_TARGET

Show more

string

quarkus.hibernate-orm."persistence-unit-name".scripts.generation.drop-target

Filename or URL where the database drop DDL file should be generated.

Environment variable: QUARKUS_HIBERNATE_ORM_SCRIPTS_GENERATION_DROP_TARGET

Show more

string

Flush configuration

デフォルト

quarkus.hibernate-orm."persistence-unit-name".flush.mode

The default flushing strategy, or when to flush entities to the database in a Hibernate session: before every query, on commit, …​

This default can be overridden on a per-session basis with Session#setHibernateFlushMode() or on a per-query basis with the hint HibernateHints#HINT_FLUSH_MODE.

See the javadoc of org.hibernate.FlushMode for details.

Environment variable: QUARKUS_HIBERNATE_ORM_FLUSH_MODE

Show more

manual, commit, auto, always

auto

期間フォーマットについて

期間の値を書くには、標準の java.time.Duration フォーマットを使います。 詳細は Duration#parse() Java API documentation を参照してください。

数字で始まる簡略化した書式を使うこともできます:

  • 数値のみの場合は、秒単位の時間を表します。

  • 数値の後に ms が続く場合は、ミリ秒単位の時間を表します。

その他の場合は、簡略化されたフォーマットが解析のために java.time.Duration フォーマットに変換されます:

  • 数値の後に hms が続く場合は、その前に PT が付けられます。

  • 数値の後に d が続く場合は、その前に P が付けられます。

application.properties 内で persistence.xmlquarkus.hibernate-orm.* プロパティーを混在させないでください。 Quarkus は例外をスローします。 どちらの方法を採用するか決めてください。

クラスパスに無視したい persistence.xml がある場合は、 次の設定プロパティーを設定してください:

quarkus.hibernate-orm.persistence-xml.ignore=true

PostgreSQLサーバをDockerで起動したいですか?

docker run --rm=true --name postgres-quarkus-hibernate -e POSTGRES_USER=hibernate \
           -e POSTGRES_PASSWORD=hibernate -e POSTGRES_DB=hibernate_db \
           -p 5432:5432 postgres:14.1

これは、永続化されない空のデータベースを起動します。簡単な実験に最適です!

複数の永続化ユニット

複数の永続化ユニットの設定

Quarkusの設定プロパティーを使用して複数の永続化ユニットを定義することができます。

quarkus.hibernate-orm. 名前空間のルートにあるプロパティーで、デフォルトの永続化ユニットを定義します。 たとえば、次のスニペットではデフォルトのデータソースとデフォルトの永続化ユニットを定義しています:

quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1

quarkus.hibernate-orm.database.generation=drop-and-create

マップをベースにした方法で名前付きの永続化ユニットを定義することができます:

quarkus.datasource."users".db-kind=h2 (1)
quarkus.datasource."users".jdbc.url=jdbc:h2:mem:users;DB_CLOSE_DELAY=-1

quarkus.datasource."inventory".db-kind=h2 (2)
quarkus.datasource."inventory".jdbc.url=jdbc:h2:mem:inventory;DB_CLOSE_DELAY=-1

quarkus.hibernate-orm."users".database.generation=drop-and-create (3)
quarkus.hibernate-orm."users".datasource=users (4)
quarkus.hibernate-orm."users".packages=org.acme.model.user (5)

quarkus.hibernate-orm."inventory".database.generation=drop-and-create (6)
quarkus.hibernate-orm."inventory".datasource=inventory
quarkus.hibernate-orm."inventory".packages=org.acme.model.inventory
1 users という名前のデータソースを定義します。
2 inventory という名前のデータソースを定義します。
3 users という永続化ユニットを定義します。
4 永続化ユニットが使用するデータソースを定義します。
5 この設定プロパティーは重要ですが、説明は少し後になります。
6 inventory データソースを指す inventory という名前の永続化ユニットを定義します。

デフォルトデータソースと名前付きデータソースを混在させることも、どちらか一方だけにすることもできます。

デフォルトの永続化ユニットは、デフォルトでデフォルトデータソースを指します。 名前付きの永続化ユニットの場合は、 datasource プロパティーが必須です。 <default> (デフォルトのデータソースの内部名) に設定することで、永続化ユニットをデフォルトデータソースを指すようにすることができます。

複数の永続化ユニットが同じデータソースを使用することもできます。

モデルクラスの永続化ユニットへのアタッチメント

モデルクラスを永続化ユニットにアタッチする方法は2つあり、混在できません:

  • packages 設定プロパティーを使用します;

  • @io.quarkus.hibernate.orm.PersistenceUnit パッケージレベルのアノテーションを使用します。

両方が混在している場合はアノテーションが無視され、 packages の設定プロパティーのみが考慮されます。

packages 設定プロパティーは簡単です:

quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.packages=org.acme.model.defaultpu

quarkus.hibernate-orm."users".database.generation=drop-and-create
quarkus.hibernate-orm."users".datasource=users
quarkus.hibernate-orm."users".packages=org.acme.model.user

この設定スニペットは2つの永続化ユニットを作成します:

  • デフォルトでは、 org.acme.model.defaultpu パッケージのすべてのモデルクラスが含まれ、サブパッケージも含まれます。

  • users という名前の永続化ユニットで、 org.acme.model.user パッケージのすべてのモデルクラスを含み、サブパッケージも含まれています。

複数のpackageを永続化ユニットにアタッチできます:

quarkus.hibernate-orm."users".packages=org.acme.model.shared,org.acme.model.user

org.acme.model.sharedorg.acme.model.user パッケージの下にあるすべてのモデル・クラスは、 users 永続化ユニットにアタッチされます。

モデルクラスを複数の永続化ユニットにアタッチすることもサポートされます。

モデルクラスは与えられた永続化ユニットに一貫して追加される必要があります。 つまり、与えられたエンティティのすべての依存するモデルクラス( @MappedSuperClass@Embeddable …​)はすべて同じ永続化ユニットにアタッチされる必要があります。 パッケージレベルで永続化ユニットを扱っているので簡単なことでしょう。

Panacheエンティティは1つの永続化ユニットにのみアタッチできます。

複数の永続化ユニットに接続されたエンティティではPanacheを使用することはできません。 しかし、この2つのアプローチを混在させることは可能で、Panacheエンティティと複数の永続化ユニットが必要な従来のエンティティを混在させることはできます。

もし、そのようなユースケースがあり、シンプルな Panache のアプローチを乱すことなく実装する方法についてすばらしいアイデアがあれば、 quarkus-dev メーリングリストまでご連絡ください。

モデルクラスを永続化ユニットにアタッチする2つ目の方法は、パッケージレベルの @io.quarkus.hibernate.orm.PersistenceUnit アノテーションを使用することです。 繰り返しになりますが、この2つのアプローチを混在させることはできません。

上記のような構成を packages の設定プロパティーで取得するには、以下の内容の package-info.java ファイルを作成します:

@PersistenceUnit("users") (1)
package org.acme.model.user;

import io.quarkus.hibernate.orm.PersistenceUnit;
1 Jakarta Persistenceのアノテーションではなく、 @io.quarkus.hibernate.orm.PersistenceUnit アノテーションを使用することに注意してください。

モデルクラスの @PersistenceUnit はパッケージレベルで定義することのみサポートしています。この場合、クラスレベルで @PersistenceUnit アノテーションを使用することはサポートされていません。

設定プロパティーで行うのと同様で、アノテーションのつけられたパッケージだけでなく、そのすべてのサブパッケージも入れていることに注意してください。

CDI インテグレーション

Quarkus で Hibernate ORM を使用することに慣れている場合は、CDI を使用してすでに EntityManager を注入しているでしょう。

@Inject
EntityManager entityManager;

これは、デフォルトの永続化ユニットの EntityManager を注入します。

名前付き永続化ユニット (この例では users) の EntityManager を注入するのは簡単です。

@Inject
@PersistenceUnit("users") (1)
EntityManager entityManager;
1 ここでも同じ @io.quarkus.hibernate.orm.PersistenceUnit アノテーションを使用しています。

まったく同じ仕組みで名前付き永続化ユニットの EntityManagerFactory を注入できます。

@Inject
@PersistenceUnit("users")
EntityManagerFactory entityManagerFactory;

永続化ユニットのアクティブ化/非アクティブ化

ビルド時に永続化ユニットが設定されている場合、 デフォルトでは実行時にもアクティブになります。 つまり、Quarkus はアプリケーションの起動時に対応する Hibernate ORM の SessionFactory を開始します。

実行時に永続化ユニットを非アクティブ化するには、 quarkus.hibernate-orm[.optional name].activefalse に設定します。 永続化ユニットがアクティブでない場合は、以下のようになります。

  • SessionFactory はアプリケーションの起動中に起動しません。

  • EntityManagerFactory/EntityManager または SessionFactory/Session にアクセスすると、例外がスローされます。

これは特に、アプリケーションが 実行時に事前に決められたデータソースのセットの中から 1 つを使用 できるようにしたい場合に便利です。

例えば、次のような設定です:

quarkus.hibernate-orm."pg".packages=org.acme.model.shared
quarkus.hibernate-orm."pg".datasource=pg
quarkus.hibernate-orm."pg".database.generation=drop-and-create
quarkus.hibernate-orm."pg".active=false
quarkus.datasource."pg".db-kind=h2
quarkus.datasource."pg".active=false
quarkus.datasource."pg".jdbc.url=jdbc:postgresql:///your_database

quarkus.hibernate-orm."oracle".packages=org.acme.model.shared
quarkus.hibernate-orm."oracle".datasource=oracle
quarkus.hibernate-orm."oracle".database.generation=drop-and-create
quarkus.hibernate-orm."oracle".active=false
quarkus.datasource."oracle".db-kind=oracle
quarkus.datasource."oracle".active=false
quarkus.datasource."oracle".jdbc.url=jdbc:oracle:///your_database

quarkus.hibernate-orm."pg".active=truequarkus.datasource."pg".active=true を実行時に 設定 すると、 PostgreSQL の永続化ユニットとデータソースのみが利用可能になり、 quarkus.hibernate-orm."oracle".active=truequarkus.datasource."oracle".active=true を実行時に設定すると、 Oracle の永続化ユニットとデータソースのみが利用可能になります。

カスタム設定プロファイル を使用すると、このようなセットアップを簡素化できます。 上記の設定に以下のプロファイル固有の設定を追加することで、 quarkus.profile=prod,pg または quarkus.profile=prod,oraclequarkus.profile を設定: して、 ランタイムに永続化ユニット/データソースを選択できます。

%pg.quarkus.hibernate-orm."pg".active=true
%pg.quarkus.datasource."pg".active=true
# Add any pg-related runtime configuration here, prefixed with "%pg."

%oracle.quarkus.hibernate-orm."oracle".active=true
%oracle.quarkus.datasource."oracle".active=true
# Add any pg-related runtime configuration here, prefixed with "%pg."

このようなセットアップでは、常に アクティブ な永続化ユニットのみをアクセスするように注意する必要があります。 そのためには、現在アクティブな名前付き Session にリダイレクトするデフォルトの SessionCDI Bean プロデューサー を定義し、直接インジェクトできるようにすることができます。以下に例を示します。

public class MyProducer {
    @Inject
    @DataSource("pg")
    InjectableInstance<AgroalDataSource> pgDataSourceBean; (1)

    @Inject
    @DataSource("oracle")
    InjectableInstance<AgroalDataSource> oracleDataSourceBean;

    @Inject
    @PersistenceUnit("pg")
    Session pgSessionBean;

    @Inject
    @PersistenceUnit("oracle")
    Session oracleSessionBean;

    @Produces (2)
    @ApplicationScoped
    public Session session() {
        if (pgDataSourceBean.getHandle().getBean().isActive()) { (3)
            return pgSessionBean;
        } else if (oracleDataSourceBean.getHandle().getBean().isActive()) { (3)
            return oracleSessionBean;
        } else {
            throw new RuntimeException("No active datasource!");
        }
    }
}

@ApplicationScoped
public class MyConsumer {
    @Inject
    Session session; (4)

    public void doSomething() {
        // .. just use the injected session ...
    }
}
1 DataSource または AgroalDatasource を直接注入しないでください。 起動時に失敗する可能性があるためです (非アクティブな Bean を注入できません)。 代わりに、 InjectableInstance<DataSource> または InjectableInstance<AgroalDataSource> を注入します。
2 アクティブなデータソースに応じて、PostgreSQL または Oracle のいずれかを デフォルトのセッションとして定義する CDI プロデューサーメソッドを宣言します。
3 対応するセッションを取得する前に、データソース Bean がアクティブか確認します。
4 これには、(唯一の) アクティブなセッションが注入されます。

persistence.xml を使用した場合のHibernate ORMのセットアップと設定

Hibernate ORM をセットアップして設定するには、using application.properties が推奨されます。 ただし、代わりに META-INF/persistence.xml ファイルを使用することもできます。 これは主に、既存のコードを Quarkus に移行する場合に役立ちます。

persistence.xml ファイルを使用する場合は、いくつかの制約が伴います。

  • persistence.xml で定義された永続化ユニットは、常に デフォルトのデータソース を使用します。

  • persistence.xml で定義された永続化ユニットは明示的に設定する必要があります。 Quarkus は環境関連の設定の注入を最小限に抑えます。

    特に、Quarkus はデータソースに基づいてダイアレクトやデータベースのバージョンを自動設定しません。 そのため、Hibernate ORM のデフォルト設定がニーズに合わない場合は、 persistence.xmlhibernate.dialect/jakarta.persistence.database-product-namejakarta.persistence.database-product-version などの設定を含める必要があります。

  • persistence.xml を使用することは、 application.properties における quarkus.hibernate-orm.* プロパティーの使用とは互換性がありません。 これらを混在させると、Quarkus は例外をスローします。

  • persistence.xml を使用する場合、using application.properties を使用する場合と比較して、利用できない機能、Quarkus ドキュメントでの限られたガイダンス、解決策を提供するエラーメッセージが適用できないこと (例: quarkus.hibernate-orm.* プロパティーの使用) などにより、開発者エクスペリエンスが悪影響を受ける可能性があります。

クラスパスに無視したい persistence.xml がある場合は、 次の設定プロパティーを設定してください:

quarkus.hibernate-orm.persistence-xml.ignore=true

pom.xml の依存関係と Java コードは先の例と同じになります。唯一の違いは META-INF/persistence.xml で Hibernate ORM の設定を行うことだけです:

persistence.xml リソースの例
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">

    <persistence-unit name="CustomerPU" transaction-type="JTA">

        <description>My customer entities</description>

        <properties>
            <!-- Connection specific -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>

            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>

            <!--
                Optimistically create the tables;
                will cause background errors being logged if they already exist,
                but is practical to retain existing data across runs (or create as needed) -->
            <property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>

            <property name="jakarta.persistence.validation.mode" value="NONE"/>
        </properties>

    </persistence-unit>
</persistence>

persistence.xml で設定を使用する場合は、Hibernate ORM を直接設定することになるので、その場合は、hibernate.org のドキュメント を参照することが適切です。

これらは Quarkus の application.properties で使用されるプロパティー名と同じではなく、同じデフォルト値が適用されるわけではありませんのでご注意ください。

XMLマッピング

Quarkus の Hibernate ORM は、XML マッピングを サポートしています。 orm.xml 形式 (Jakarta Persistence) または hbm.xml 形式 (Hibernate ORM 固有、非推奨化) に従ってマッピングファイルを追加できます。

XML マッピングファイルは、ビルド時に解析されます。

META-INF/orm.xml ファイルがクラスパスに存在する場合は、常にデフォルトでインクルードされます。

それが望ましくない場合は、 quarkus.hibernate-orm.mapping-files = no-file または <mapping-file>no-file</mapping-file> を使用します。

外部プロジェクトや jar でエンティティーを定義する

QuarkusのHibernate ORMは、エンティティーに対するコンパイル時のバイトコード強化に依存しています。Quarkusアプリケーションを構築するのと同じプロジェクトでエンティティーを定義すれば、すべてがうまく動作します。

エンティティーが外部のプロジェクトやジャーから来ている場合は、空の META-INF/beans.xml ファイルを追加することで、jarがQuarkusアプリケーションライブラリのように扱われるようにすることができます。

これにより、Quarkusは、エンティティが現在のプロジェクトの内部にあるかのようにインデックスを作成し、バイトコード強化をすることができます。

開発モードでのHibernate ORM

Quarkusの開発モードはフロントエンドやサービス、データベースアクセスが混在するアプリケーションにとても便利です。

それを生かすためにはいくつかの共通したアプローチがあります。

1つ目の選択肢は、 quarkus.hibernate-orm.database.generation=drop-and-createimport.sql を併用することです。

そうすることで、アプリケーション、特にエンティティに変更があるたびに、データベーススキーマが適切に再作成され、データフィクスチャ( import.sql に保存)がゼロから再投入されます。これは環境を完全にコントロールするための最良の方法であり、Quarkusのライブリロードモードでは魔法のように機能します。エンティティの変更や import.sql へのあらゆる変更が即座に反映され、アプリケーションを再起動しなくてもスキーマが更新されます!

dev および test モードのデフォルトでは、Hibernate ORM は起動時に /import.sql ファイル内の SQL 文を読み込んで実行します(存在する場合)。 application.properties のプロパティー quarkus.hibernate-orm.sql-load-script を変更することで、ファイル名を変更することができます。

2つ目の選択肢は quarkus.hibernate-orm.database.generation=update を使用することです。 この方法は、多くのエンティティを変更するが本番データのコピーで作業する必要がある場合や、特定のデータベースのデータエントリーに基づくバグを再現する場合に最適です。 update は Hibernate ORM によってベストエフォートで実行され、データ損失につながるデータベース構造の変更を含む特定の状況では失敗します。 例えば、外部キー制約に違反する構造を変更する場合、Hibernate ORM の挙動を助けてあげなければならないかもしれません。 しかし、開発中だとこれらの制限は許容範囲内です。

3つ目の選択肢は quarkus.hibernate-orm.database.generation=none を使用することです。この方法は、本番データのコピーで作業しており、スキーマの変更を完全にコントロールしたい場合に最適です。あるいは、 FlywayLiquibaseのようなデータベーススキーマ移行ツールを使用している場合です。

この方法では、エンティティに変更を加える時にデータベーススキーマに確実に適合させる必要があります。また、 validate を使用して、Hibernateにスキーマが期待どおりかを確認させることもできます。

本番環境では、 quarkus.hibernate-orm.database.generationdrop-and-createupdate は使用しないでください。

これらの方法は、Quarkusの設定プロファイルと組み合わせることで非常に強力になります。異なる 設定プロファイルを定義して、環境に応じて異なる動作を選択することができます。これは、現在必要としている開発スタイルに合わせて、Hibernate ORMのプロパティーの異なる組み合わせを定義できるという点で素晴らしいことです。

application.properties
%dev.quarkus.hibernate-orm.database.generation = drop-and-create
%dev.quarkus.hibernate-orm.sql-load-script = import-dev.sql

%dev-with-data.quarkus.hibernate-orm.database.generation = update
%dev-with-data.quarkus.hibernate-orm.sql-load-script = no-file

%prod.quarkus.hibernate-orm.database.generation = none
%prod.quarkus.hibernate-orm.sql-load-script = no-file

カスタムプロファイルを使用して開発モードを開始することができます:

コマンドラインインタフェース
quarkus dev -Dquarkus.profile=dev-with-data
Maven
./mvnw quarkus:dev -Dquarkus.profile=dev-with-data
Gradle
./gradlew --console=plain quarkusDev -Dquarkus.profile=dev-with-data

本番モードでのHibernate ORM

Quarkusにはデフォルトのプロファイルが付属しています ( dev , testprod )。また、様々な環境を記述するために独自のカスタムプロファイルを追加することができます ( staging , prod-us , など )。

Hibernate ORM Quarkusエクステンションでは、いくつかのデフォルト設定が、開発モードとテストモードで他の環境とは異なるように設定されています。

  • devtest 以外のプロフィールは quarkus.hibernate-orm.sql-load-scriptno-file に設定されています。

application.properties で明示的にオーバーライドできます。 (例: %prod.quarkus.hibernate-orm.sql-load-script = import.sql) ただし、 実稼働環境で誤ってデータベースをオーバーライドすることは避けたいと考えています :)

ところで、実稼働環境でデータベーススキーマを削除しないようにしてください。 プロパティーファイルに以下を追加してください。

application.properties
%prod.quarkus.hibernate-orm.database.generation = none
%prod.quarkus.hibernate-orm.sql-load-script = no-file

スキーマを管理するためのFlywayへの自動移行

開発モードでで実行している際に Flyway エクステンション をインストールしている場合、 Quarkus は Hibernate ORM によって自動的に生成されたスキーマを使用して Flyway の設定を簡単に初期化する方法を提供します。 これは、Hibernate を使ってスキーマを迅速にセットアップできる初期開発段階から、 Flyway を使ってスキーマの変更を管理する実稼働段階への移行を 容易にすることを目的としています。

この機能を使用するには、 quarkus-flyway エクステンションがインストールされている状態で Dev UI を開き、Flyway ペインの Datasources リンクをクリックします。 Create Initial Migration ボタンを押すと、以下が実行されます。

  • Hibernate がスキーマを生成するために実行している SQL を含む db/migration/V1.0.0__{appname}.sql ファイルが作成されます。

  • quarkus.flyway.baseline-on-migrate が設定され、Flyway がベースラインとなるテーブルを自動的に作成するようになります。

  • quarkus.flyway.migrate-at-start が設定され、アプリケーションの起動時に Flyway が自動的にマイグレーションを適用するようになります。

  • %dev.quarkus.flyway.clean-at-start%test.quarkus.flyway.clean-at-start が設定され、開発/テストモードでリロードした後に DB をクリーンアップします。

このボタンはFlywayを素早く使い始めるためのものであり、本番環境でデータベーススキーマをどのように管理するかはユーザー次第です。特に migrate-at-start の設定はすべての環境に適しているとは限りません。

キャッシング

同じエンティティを頻繁に読み込むアプリケーションでは、Hibernate ORMのL2キャッシュを有効にするとパフォーマンスが向上します。

エンティティのキャッシュ

セカンドレベルキャッシュを有効にするには、キャッシュさせたいエンティティを @jakarta.persistence.Cacheable でマークします:

@Entity
@Cacheable
public class Country {
    int dialInCode;
    // ...
}

エンティティが @Cacheable でアノテーションされているときは、コレクションと他のエンティティとの関係を除いて、そのすべてのフィールド値がキャッシュされます。

これは、データベースに問い合わせることなくエンティティをロードできることを意味しますが、ロードされたエンティティがデータベースの最近の変更を反映していない可能性があることを意味するので注意が必要です。

コレクションとリレーションのキャッシング

コレクションとリレーションはキャッシュするために個別にアノテーションする必要があります。この場合、Hibernate固有の @org.hibernate.annotations.Cache を使用する必要があり、さらに CacheConcurrencyStrategy を指定する必要があります:

package org.acme;

@Entity
@Cacheable
public class Country {
    // ...

    @OneToMany
    @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
    List<City> cities;

    // ...
}

クエリのキャッシュ

クエリもL2キャッシュの恩恵を受けることができます。キャッシュされたクエリの結果は即座に呼び出し元に返すことができるので、データベース上でクエリを実行する必要がありません。

最近の変化を反映していない可能性があることを含意しているので注意が必要です。

クエリをキャッシュするには、 Query インスタンス上でキャッシュ可能なものとしてマークします:

Query query = ...
query.setHint("org.hibernate.cacheable", Boolean.TRUE);

NamedQuery があれば、その定義で直接キャッシュを有効にすることができます。これは通常、エンティティ上で行われます:

@Entity
@NamedQuery(name = "Fruits.findAll",
      query = "SELECT f FROM Fruit f ORDER BY f.name",
      hints = @QueryHint(name = "org.hibernate.cacheable", value = "true") )
public class Fruit {
   ...

以上です。キャッシュ技術はすでにQuarkusに統合されてデフォルトで有効になってるのでキャッシュしても問題ないものを設定するだけで十分です。

キャッシュ領域の調整

キャッシュはデータの異なる部分を分離するために別々の領域にデータを保存します。このような領域には名前が付けられ、各領域を独立して設定したり、統計を監視したりするのに役立ちます。

デフォルトでは、エンティティは、その完全修飾名を冠した領域(例えば、 org.acme.Country)にキャッシュされます。

org.acme.Country#cities コレクションは保持するエンティティの完全修飾名とコレクションのフィールド名を # 文字で区切った名前の領域にキャッシュされます。

すべてのキャッシュされたクエリは、デフォルトでは、 default-query-results-region と呼ばれる一つの専用の領域に保存されます。

すべてのリージョンは、デフォルトではサイズと時間で制限されています。デフォルトでは、最大で 10000 のエントリ数、最大で 100 秒のアイドル時間が設定されています。

各リージョンのサイズは、 quarkus.hibernate-orm.cache."<region_name>".memory.object-count プロパティーを介してカスタマイズできます (<region_name> は実際のリージョン名に置き換えます)。

最大アイドル時間を設定するには、 quarkus.hibernate-orm.cache."<region_name>".expiration.max-idle プロパティー (<region_name> は実際のリージョン名に置き換えます) を介して時間 (下記の時間のフォーマットに関する注意を参照) を指定します。

領域名にドットが含まれている場合は二重引用符が必須です。次のようになります:

quarkus.hibernate-orm.cache."org.acme.MyEntity".memory.object-count=1000

期間の値を書くには、標準の java.time.Duration フォーマットを使います。 詳細は Duration#parse() javadoc を参照してください。

数字で始まる簡略化した書式を使うこともできます:

  • 数値のみの場合は、秒単位の時間を表します。

  • 数値の後に ms が続く場合は、ミリ秒単位の時間を表します。

その他の場合は、簡略化されたフォーマットが解析のために java.time.Duration フォーマットに変換されます:

  • 数値の後に hms が続く場合は、その前に PT が付けられます。

  • 数値の後に d が続く場合は、その前に P が付けられます。

キャッシュの制限

Quarkusで提供されているキャッシュ技術は現在のところ非常に初歩的で制約があります。

Quarkusの開発チームは最初から ある程度の キャッシュ機能があった方が何もないよりは良いと考えました。将来のリリースではより良いキャッシュソリューションが統合されることを期待しています。

これらのキャッシュはローカルに保持されているため、他のアプリケーションによって永続ストアに変更が加えられても無効化されたり更新されたりすることはありません。

また、同じアプリケーションの複数のコピーを(Kubernetes/OpenShiftなどのクラスタで)実行している場合、アプリケーションの別々のコピーのキャッシュは同期されません。

これらの理由から、ある種の仮定が成り立つ場合にのみキャッシュを有効にすることが適しています。私たちは、変化しないエンティティ、コレクション、およびクエリのみをキャッシュすることを強く推奨します。あるいは、そのようなエンティティが実際に変更され、古くなった(stale)ものを読み取ったとしても、アプリケーションの期待値に影響を与えないようにする必要があります。

このアドバイスに従うことで、アプリケーションがL2キャッシュから最高のパフォーマンスを引き出し、かつ予期せぬ動作を避けることができます。

不変のデータだけでなく、ある文脈では、可変のデータに対してもキャッシュを有効にすることが許容されるかもしれません。これは、頻繁に読み込まれ、ある程度の陳腐化を許容できるようなエンティティを選択した場合、必要なトレードオフとなり得ます。この「許容される陳腐化の度合い」は、eviction プロパティーを設定することで調整できます。しかし、これは推奨されておらず、データに予期せぬ影響を与える可能性があるため、細心の注意を払って行う必要があります。

理想的には、変更可能なデータでキャッシュを有効にするのではなく、クラスタ化されたキャッシュを使用することがより良い解決策です。しかし、現時点では、Quarkusはそのような実装を提供していません:この必要性を知らせれば、チームがこれを考慮することができますので、お気軽にご連絡ください。

最後に、 hibernate.cache.use_second_level_cachefalse に設定することで、L2 キャッシュをグローバルで無効化できます。この設定は、 persistence.xml 設定ファイルで指定する必要があります。

L2キャッシュを無効にすると、すべてのキャッシュアノテーションは無視され、すべてのクエリはキャッシュを無視して実行されます。これは通常、問題を診断する場合にのみ有効です。

Hibernate Envers

Hibernate ORMのEnversエクステンションは、エンティティクラスのための簡単な監査/バージョン管理ソリューションを提供することを目的としています。

Quarkusでは、Enversには専用のQuarkus エクステンションがあります。 io.quarkus:quarkus-hibernate-envers ; これをプロジェクトに追加して使用を開始する必要があります。

Hibernate Enversを有効にするための追加の依存関係
    <!-- Add the Hibernate Envers extension -->
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-hibernate-envers</artifactId>
    </dependency>

Quarkusの設定プロパティーを使用して、複数の永続化ユニットを定義することができます。

Hibernate Envers の詳細については、hibernate.org/orm/envers/ を参照してください。

メトリクス

Micrometer または SmallRye Metrics は、 Hibernate ORM が実行時に収集するメトリクスを公開できます。Hibernate のメトリクスを /q/metrics エンドポイントで公開するには、 プロジェクトがメトリクスエクステンションに依存しており、設定プロパティー quarkus.hibernate-orm.metrics.enabledtrue に設定していることを確認します。 SmallRye Metrics を使用している場合、メトリクスは vendor スコープ内で利用可能になります。

制限事項など知っておくべきこと

Quarkusは使用するライブラリを変更しません。このルールはHibernate ORMにも適用されます。このエクステンションを使用すると、元のライブラリを使用した場合とほとんど同じエクスペリエンスが得られます。

ただし、同じコードを共有しているものの、Quarkus は一部のコンポーネントを自動的に設定し、いくつかのエクステンション ポイントに対してカスタム実装を注入します。これは透過的で便利なはずですが、Hibernate のエキスパートであれば、 何が行われているかを知りたいかもしれません。

自動ビルド時間の強化

Hibernate ORMでは、ビルド時に拡張されたエンティティを使用できます。通常、これは必須ではありませんが便利でアプリケーションのパフォーマンスを向上させることができます。

通常は、ビルドスクリプトにHibernate Enhancementプラグインを含める必要がありますが、QuarkusではEnhancementステップがQuarkusアプリケーションのビルドと分析に統合されているため、その必要はありません。

Enhancement を使用しているため、エンティティで clone() メソッドを使用することは現在サポートされていません。これは、エンティティにEnhancement 固有のフィールドもクローンされるためです。

この制限は将来的に削除される可能性があります。

自動統合

トランザクションマネージャーの統合

これを設定する必要はありません。Quarkus は自動的に Narayana Transaction Manager への参照を注入します。この依存関係は、Hibernate ORM エクステンションの推移的依存関係として自動的に含まれます。すべての設定はオプションです。詳細は、Quarkusでのトランザクションの使用 を参照してください。

コネクションプール

どちらかを選択する必要はありません。上記の例のようにデータソースを設定するだけで、Hibernate ORMがAgroalを使用するように設定されます。このコネクションプールの詳細については、 Quarkus - データソースを参照してください。

L2キャッシュ

前述の Caching section で説明したように、実装を選択する必要はありません。 InfinispanCaffeine の技術に基づく適切な実装が Hibernate ORM エクステンションの遷移依存関係として含まれており、ビルド時に自動的に統合されます。

制限

クラスパスに重複したファイルがある場合のXMLマッピング

XML mapping ファイルは一意のパスを持つことが期待されます。

実際には、クラスパスに XML マッピングファイルを重複して配置するのは、非常に特殊なシナリオの場合のみです。たとえば、2つのJARに(まったく同じパスで異なるJARにある) META-INF/orm.xml ファイルが含まれている場合、マッピングファイルのパス META-INF/orm.xml は、 <code>META-INF/orm.xml</code> ファイルと同じJARpersistence.xml からしか参照できません。

JMX

管理 Bean は GraalVM ネイティブイメージでは動作しません。したがって、ネイティブイメージにコンパイルすると、JMX Bean に統計と管理操作を登録する Hibernate の機能は無効になります。ネイティブ・イメージがJMXのサポートを実装することは目標ではないので、この制限は永久に続くと思われます。このようなメトリクスはすべて、他の方法でアクセスすることができます。

JACCの統合

GraalVMのネイティブイメージを構築する際には、JACCと統合するHibernate ORMの機能は無効になります。なぜなら、JACCはネイティブ・モードでは利用できず、有用でもないからです。

セッションをThreadLocalコンテキストにバインドする

Hibernate ORM の ThreadLocalSessionContext ヘルパーは、サポートが実装されていないため使用できません。 Quarkus は CDI サポートを最初から提供しているので、注入やプログラムによる CDI ルックアップがより良いアプローチとなります。 この機能は、リアクティブコンポーネントやより最新のコンテキスト伝播技術ともうまく統合されなかったため、このレガシー機能には将来性がないと考えられます。 どうしても ThreadLocal にバインドする必要がある場合は、独自のコードで簡単に実装できるはずです。

JNDI

JNDI技術は、異なるコンポーネントを統合するために他のランタイムで一般的に使用されています。一般的な使用例は、Java EnterpriseサーバーでTransactionManagerとDatasourceコンポーネントを名前にバインドし、Hibernate ORMがこれらのコンポーネントを名前で検索するように設定することです。しかし、Quarkusでは、コンポーネントが直接注入されるため、このユースケースは適用されず、JNDIサポートは不要なレガシーとなります。JNDIの予期せぬ使用を避けるため、QuarkusのHibernate ORMエクステンションでは、JNDIの完全なサポートは無効になっています。これは、セキュリティ上の予防策であり、最適化でもあります。

その他の特記すべき相違点

import.sql のフォーマット

データベースをセットアップするために import.sql をインポートする際、QuarkusはHibernate ORMを再構成し、各ステートメントの最後にセミコロン( ';' )を必要とすることに留意してください。Hibernateのデフォルトでは、改行以外の終端文字を必要とせず、1行に1つのステートメントがあります。既存のスクリプトを再利用する場合は、終端文字として「;」を使用するようにスクリプトを変換することを忘れないでください。これは、複数行のステートメントを可能にし、人間が使いやすいフォーマットにするために役立ちます。

Simplified Hibernate ORM with Panache

Hibernate ORM with Panache エクステンションはアクティブレコードスタイルのエンティティ(およびリポジトリ)を提供してHibernate ORMを簡単に使えるようにし、Quarkusでエンティティを簡単に楽しく書けるようにすることに重点を置いています。

データソースの設定

データソースの設定は非常にシンプルですが、技術的にはQuarkus用のAgroal接続プールエクステンションによって実装されているため、別のガイドで説明します。

詳細は Quarkus - データソースをご覧ください。

マルチテナンシー

「マルチテナンシーという用語は、一般的にソフトウェア開発において、1 つの実行中のアプリケーションインスタンスが複数のクライアント (テナント) に同時にサービスを提供するアーキテクチャーを指します。これは SaaS ソリューションにおいて非常に一般的です。こうしたシステムでは、各テナントに関連する情報 (データ、カスタマイズなど) を分離することが特に課題となります。これには、データベースに保存される各テナントが所有するデータの分離も含まれます」 (Hibernate ユーザーガイド)

Quarkus は現在、別々のデータベース を使用する方法、別々のスキーマ を使用する方法、および discriminator を使用する方法をサポートしています。

マルチテナンシーの動作を確認するには、 hibernate-orm-multi-tenancy-schema-quickstart または hibernate-orm-multi-tenancy-database-quickstart をご覧ください。

アプリケーションの記述

/{tenant} エンドポイントを実装することから始めます。以下のソースコードからわかるように、これは単なる通常の Jakarta REST リソースです。

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@ApplicationScoped
@Path("/{tenant}")
public class FruitResource {

    @Inject
    EntityManager entityManager;

    @GET
    @Path("fruits")
    public Fruit[] getFruits() {
        return entityManager.createNamedQuery("Fruits.findAll", Fruit.class)
                .getResultList().toArray(new Fruit[0]);
    }

}

受信したリクエストからテナントを解決し、特定のテナント構成にマッピングするためには、 io.quarkus.hibernate.orm.runtime.tenant.TenantResolver インターフェースの実装を作成する必要があります。

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.hibernate.orm.runtime.tenant.TenantResolver;
import io.vertx.ext.web.RoutingContext;

@PersistenceUnitExtension (1)
@RequestScoped (2)
public class CustomTenantResolver implements TenantResolver {

    @Inject
    RoutingContext context;

    @Override
    public String getDefaultTenantId() {
        return "base";
    }

    @Override
    public String resolveTenantId() {
        String path = context.request().path();
        String[] parts = path.split("/");

        if (parts.length == 0) {
            // resolve to default tenant config
            return getDefaultTenantId();
        }

        return parts[1];
    }

}
1 TenantResolverの実装に @PersistenceUnitExtension という修飾語を付けて、Quarkusにデフォルトの永続化ユニットで使用することを伝えます。

named persistence units の場合は、 @PersistenceUnitExtension("nameOfYourPU") を使用します。

2 Beanは、テナントの解決が入ってくるリクエストに依存するため @RequestScoped にします。

上記の実装ではテナントはリクエストパスから解決されるので、テナントが推測できない場合はデフォルトのテナント識別子が返されます。

OIDC マルチテナンシー も使用しており、OIDC と Hibernate ORM のテナント ID が同じ場合は、 以下の例のように RoutingContext 属性から OIDC のテナント ID を取得できます。

import io.quarkus.hibernate.orm.runtime.tenant.TenantResolver;
import io.quarkus.oidc.runtime.OidcUtils;
import io.vertx.ext.web.RoutingContext;

@PersistenceUnitExtension
@RequestScoped
public class CustomTenantResolver implements TenantResolver {

    @Inject
    RoutingContext context; (1)
    ...
    @Override
    public String resolveTenantId() {
        // OIDC has saved the tenant id as the RoutingContext attribute:
        return context.get(OidcUtils.TENANT_ID_ATTRIBUTE);
    }
}
1 Hibernate の TenantResolver`がアクティブな HTTP リクエストがない場合でもテナントを解決する場合、 たとえば、スケジューラーからデータベースをクエリーする場合、 `RoutingContext CDI Bean は使用できません。 代わりに io.quarkus.vertx.http.runtime.CurrentVertxRequest CDI Bean を注入し、この Bean から RoutingContext を取得してください。

アプリケーションの設定

一般的に、Hibernate ORMのデータベース生成機能をマルチテナンシーのセットアップと組み合わせて使用することはできません。そのため、この機能を無効にして、テーブルがスキーマごとに作成されるようにする必要があります。以下のセットアップでは、 Flyway エクステンションを使用してこの目的を達成します。

SCHEMAアプローチ

すべてのテナントに同じデータソースが使用され、そのデータソース内のすべてのテナントに対してスキーマを作成する必要があります。

MariaDB/MySQL などの一部のデータベースはデータベーススキーマをサポートしていません。このような場合は、database approach を使用する必要があります。
quarkus.hibernate-orm.database.generation=none (1)

quarkus.hibernate-orm.multitenant=SCHEMA (2)

quarkus.datasource.db-kind=postgresql (3)
quarkus.datasource.username=quarkus_test
quarkus.datasource.password=quarkus_test
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test

quarkus.flyway.schemas=base,mycompany (4)
quarkus.flyway.locations=classpath:schema
quarkus.flyway.migrate-at-start=true
1 スキーママルチテナンシーでは Hibernate ORM によってサポートされていないため、スキーマ生成を無効にします。 代わりに Flyway を使用します。詳細は下記を参照してください。
2 スキーマのマルチテナンシーを有効にします。

ここではデフォルトのデータソースを使用していますが、there の指示に従って、名前付きのデータソースを使用することもできます。

3 データソースを設定します
4 この場合、Hibernate ORM によるスキーマ生成がサポートされていないため、 Flyway をデータベースの初期化用に設定します。

ここでは、設定されたフォルダー src/main/resources/schema に作成される Flyway SQL ( V1.0.0__create_fruits.sql ) の例を示します。

CREATE SEQUENCE base.known_fruits_id_seq;
SELECT setval('base."known_fruits_id_seq"', 3);
CREATE TABLE base.known_fruits
(
  id   INT,
  name VARCHAR(40)
);
INSERT INTO base.known_fruits(id, name) VALUES (1, 'Cherry');
INSERT INTO base.known_fruits(id, name) VALUES (2, 'Apple');
INSERT INTO base.known_fruits(id, name) VALUES (3, 'Banana');

CREATE SEQUENCE mycompany.known_fruits_id_seq;
SELECT setval('mycompany."known_fruits_id_seq"', 3);
CREATE TABLE mycompany.known_fruits
(
  id   INT,
  name VARCHAR(40)
);
INSERT INTO mycompany.known_fruits(id, name) VALUES (1, 'Avocado');
INSERT INTO mycompany.known_fruits(id, name) VALUES (2, 'Apricots');
INSERT INTO mycompany.known_fruits(id, name) VALUES (3, 'Blackberries');

データベースアプローチ

すべてのテナントに対して、 TenantResolver が返すのと同じ識別子を持つ名前付きデータソースを作成する必要があります。

このアプローチでは、同じ永続化ユニットで使用されるすべてのデータソースが、 同じベンダー (同じ db-kind) およびバージョンのデータベースを指すと仮定されます。

不一致は検出されず、予期しない動作が発生する可能性があります。

quarkus.hibernate-orm.database.generation=none (1)

quarkus.hibernate-orm.multitenant=DATABASE (2)
quarkus.hibernate-orm.datasource=base (3)

# Default tenant 'base'
quarkus.datasource.base.db-kind=postgresql (4)
quarkus.datasource.base.username=quarkus_test
quarkus.datasource.base.password=quarkus_test
%prod.quarkus.datasource.base.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test
quarkus.flyway.base.locations=classpath:database/base (5)
quarkus.flyway.base.migrate-at-start=true

# Tenant 'mycompany'
quarkus.datasource.mycompany.db-kind=postgresql (6)
quarkus.datasource.mycompany.username=mycompany
quarkus.datasource.mycompany.password=mycompany
%prod.quarkus.datasource.mycompany.jdbc.url=jdbc:postgresql://localhost:5433/mycompany
quarkus.flyway.mycompany.locations=classpath:database/mycompany (7)
quarkus.flyway.mycompany.migrate-at-start=true
1 データベースのマルチテナンシーには Hibernate ORM によるスキーマ生成がサポートされていないため、スキーマ生成を無効にします。代わりに Flyway を使用します。詳細は下記を参照してください。
2 データベースのマルチテナンシーを有効にします。
3 永続化ユニットのデータソースを選択します。

これは、Quarkus が使用する Hibernate ORM のダイアレクトを決定できるようにすることのみを目的としています。 詳細は、this section を参照してください。

4 1 つのテナント、 base 用に データソースを設定 します。
5 この場合、Hibernate ORM によるスキーマ生成はサポートされていないため、 テナント base のデータベース初期化用に Flyway を設定します。
6 別のテナントの データソースを設定します

他にもテナントがあるかもしれませんが、ここでは 2 つで止めています。

7 この場合、Hibernate ORM によるスキーマ生成はサポートされていないため、 テナント mycompany のデータベース初期化用に Flyway を設定します。

以下は、設定されたフォルダー src/main/resources/database に作成する Flyway SQL ファイルの例です。

テナント base のスキーマ (src/main/resources/database/base/V1.0.0__create_fruits.sql):

CREATE SEQUENCE known_fruits_id_seq;
SELECT setval('known_fruits_id_seq', 3);
CREATE TABLE known_fruits
(
  id   INT,
  name VARCHAR(40)
);
INSERT INTO known_fruits(id, name) VALUES (1, 'Cherry');
INSERT INTO known_fruits(id, name) VALUES (2, 'Apple');
INSERT INTO known_fruits(id, name) VALUES (3, 'Banana');

テナント mycompany のスキーマ (src/main/resources/database/mycompany/V1.0.0__create_fruits.sql):

CREATE SEQUENCE known_fruits_id_seq;
SELECT setval('known_fruits_id_seq', 3);
CREATE TABLE known_fruits
(
  id   INT,
  name VARCHAR(40)
);
INSERT INTO known_fruits(id, name) VALUES (1, 'Avocado');
INSERT INTO known_fruits(id, name) VALUES (2, 'Apricots');
INSERT INTO known_fruits(id, name) VALUES (3, 'Blackberries');

DISCRIMINATOR アプローチ

デフォルトのデータソースがすべてのテナントに使用されます。 @TenantId でアノテーションされたフィールドを定義しているすべてのエンティティには、そのフィールドが自動的に入力され、クエリで自動的にフィルタリングされます。

quarkus.hibernate-orm.multitenant=DISCRIMINATOR (1)

quarkus.datasource.db-kind=postgresql (2)
quarkus.datasource.username=quarkus_test
quarkus.datasource.password=quarkus_test
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test
1 discriminator マルチテナンシーを有効にします。
2 データソースを設定します

テナント接続をプログラムで解決

サポートするテナントごとにより動的な設定が必要で、設定ファイルに複数のエントリーを追加したくない場合は、 io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver インターフェイスを使用して、接続を取得する独自のロジックを実装できます。 このインターフェースを実装するアプリケーションスコープの Bean を作成し、 @PersistenceUnitExtension (または named persistence unit の場合は @PersistenceUnitExtension("nameOfYourPU") のアノテーションをを付与すると、 Quarkus のデフォルト実装 io.quarkus.hibernate.orm.runtime.tenant.DataSourceTenantConnectionResolver を置き換えます。 カスタム接続リゾルバーを使用すると、たとえば、テナント情報をデータベースから読み取り、それに基づいてテナントごとに実行時に接続を作成することが可能になります。

インターセプター

適切な修飾子を持つ CDI Bean を定義するだけで、org.hibernate.InterceptorSessionFactory に割り当てることができます。

@PersistenceUnitExtension (1)
public static class MyInterceptor extends EmptyInterceptor { (2)
    @Override
    public boolean onLoad(Object entity, Serializable id, Object[] state, (3)
            String[] propertyNames, Type[] types) {
        // ...
        return false;
    }
}
1 インターセプターの実装に @PersistenceUnitExtension の修飾子を付けて、Quarkusにデフォルトの永続化ユニットで使用されるように伝えます。

named persistence units の場合は、 @PersistenceUnitExtension("nameOfYourPU") を使用します。

2 org.hibernate.EmptyInterceptor を拡張するか、 org.hibernate.Interceptor を直接実装します。
3 必要に応じてメソッドを実装します。

デフォルトでは、 @PersistenceUnitExtension アノテーションの付けられたインターセプター Beanはアプリケーションスコープになります。つまり、アプリケーションごとにインターセプターのインスタンスが一つのみ作成され、すべてのエンティティマネージャーで再利用されます。このため、インターセプターの実装はスレッドセーフである必要があります。

エンティティマネージャーごとに1つのインターセプターのインスタンスを作成するには、Beanに @Dependent アノテーションを付けます。この場合はインターセプターの実装はスレッドセーフである必要はありません。

Hibernate ORM 自体の制限により、 @Dependent スコープのインターセプターの @PreDestroy メソッドは決して呼び出されません。

ステートメントインスペクター

適切な修飾子を持つCDI Beanを定義するだけで、 SessionFactoryorg.hibernate.engine.jdbc.spi.StatementInspector を割り当てることができます:

@PersistenceUnitExtension (1)
public class MyStatementInspector implements StatementInspector { (2)
    @Override
    public String inspect(String sql) {
        // ...
        return sql;
    }
}
1 ステートメントインスペクターの実装に @PersistenceUnitExtension という修飾子を付けて、Quarkus にデフォルトの永続化ユニットで使用するように指示します。

named persistence units の場合は、 @PersistenceUnitExtension("nameOfYourPU") を使用します。

2 org.hibernate.engine.jdbc.spi.StatementInspector を実装してください。

JSON/XML シリアル化/デシリアル化のカスタマイズ

デフォルトでは、Quarkus は利用可能なエクステンションに応じてフォーマットマッパーを自動的に設定しようとします。 Jackson (または JSON-B) が利用可能な場合、グローバルに設定された ObjectMapper (または Jsonb) がシリアル化/デシリアル化操作に使用されます。 Jackson と JSON-B の両方が同時に使用可能な場合は、Jackson が優先されます。

Hibernate ORM における JSON および XML のシリアル化/デシリアル化は、 org.hibernate.type.format.FormatMapper を実装し 適切な修飾子を使用して実装にアノテーションを付けることでカスタマイズできます。

import io.quarkus.hibernate.orm.JsonFormat;
import org.hibernate.type.format.FormatMapper;

@JsonFormat (1)
@PersistenceUnitExtension (2)
public class MyJsonFormatMapper implements FormatMapper { (3)
    @Override
    public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        // ...
    }

    @Override
    public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
       // ...
    }
}
1 フォーマットマッパーの実装に @JsonFormat 修飾子のアノテーションを付与し、 このマッパーが JSON のシリアル化/デシリアル化固有であることを Quarkus に知らせます。
Jackson のアノテーシではなく、 Quarkus 固有の @io.quarkus.hibernate.orm.JsonFormat アノテーションが使用されていることを確認します。
2 フォーマットマッパーの実装に @PersistenceUnitExtension 修飾子のアノテーションを付与し、 これがデフォルトの永続化ユニットで使用されるべきものであることを Quarkus に知らせます。

named persistence units の場合は、 @PersistenceUnitExtension("nameOfYourPU") を使用します。

3 org.hibernate.type.format.FormatMapper を実装します。

カスタム XML 形式マッパーの場合は、別の CDI 修飾子を適用する必要があります。

import io.quarkus.hibernate.orm.XmlFormat;
import org.hibernate.type.format.FormatMapper;

@XmlFormat (1)
@PersistenceUnitExtension (2)
public class MyJsonFormatMapper implements FormatMapper { (3)
    @Override
    public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        // ...
    }

    @Override
    public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
       // ...
    }
}
1 このマッパーが XML のシリアライズ/デシリアライズ専用であることを Quarkus に知らせるために、フォーマットマッパーの実装に @XmlFormat 修飾子のアノテーションを付与します。
2 フォーマットマッパーの実装に @PersistenceUnitExtension 修飾子のアノテーションを付与し、 これがデフォルトの永続化ユニットで使用されるべきものであることを Quarkus に知らせます。

named persistence units の場合は、 @PersistenceUnitExtension("nameOfYourPU") を使用します。

3 org.hibernate.type.format.FormatMapper を実装します。

フォーマットマッパーには、 @PersistenceUnitExtension と、 @JsonFormat または @XmlFormat CDI 修飾子のいずれかが適用されている 必要 があります。

同じ永続化ユニットに複数の JSON (または XML) 形式マッパーを登録すると、あいまいさのために例外が発生します。

関連コンテンツ