The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Hibernate ORMとJPAの使用

Hibernate ORMは、デファクトスタンダートのJPA実装であり、オブジェクトリレーショナルマッパーのすべてを提供します。これはQuarkusで美しく動作します。

ソリューション

次のセクションの指示に従って、段階的にアプリケーションを作成していくことをお勧めします。ただし、完成した例にすぐにアクセスすることもできます。

Gitリポジトリをクローンする: git clone https://github.com/quarkusio/quarkus-quickstarts.git 、または 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 の例
# datasource configuration
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = hibernate
quarkus.datasource.password = hibernate
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/hibernate_db

# drop and create the database at startup (use `update` to only update the schema)
quarkus.hibernate-orm.database.generation=drop-and-create

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

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

application.properties で設定できるプロパティのリストについては、以下の Hibernate ORM 設定プロパティ のセクションを参照してください。

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

方言(dialect)は、明示的に設定しない限りはJDBCドライバに基づいて選択されます。

その後、 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 エンドポイントコントローラーのように、アプリケーションのエントリーポイントの境界でこれを行うことをお勧めします。

Hibernate ORMの設定プロパティ

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

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

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

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

ビルド時に固定される設定プロパティ - それ以外の設定プロパティは実行時に上書き可能

Configuration property

タイプ

デフォルト

Environment variable: QUARKUS_HIBERNATE_ORM_DATASOURCE

string

Environment variable: QUARKUS_HIBERNATE_ORM_PACKAGES

list of string

Path to a file containing the SQL statements to execute when Hibernate ORM starts.

The file is retrieved from the classpath resources, so it 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

list of string

import.sql in DEV, TEST ; no-file otherwise

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

string

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

string

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

string

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

list of string

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

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

boolean

true

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

string

Defines the name of the datasource to use in case of SCHEMA approach. The datasource of the persistence unit will be used if not set.

Environment variable: QUARKUS_HIBERNATE_ORM_MULTITENANT_SCHEMA_DATASOURCE

string

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

boolean

true

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

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

boolean

Whether metrics are published if a metrics extension is enabled.

Environment variable: QUARKUS_HIBERNATE_ORM_METRICS_ENABLED

boolean

false

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

Map<String,String>

Dialect related configuration

タイプ

デフォルト

Class name of the Hibernate ORM dialect. The complete list of bundled dialects is available in the Hibernate ORM JavaDoc.

Not all the dialects are supported in GraalVM native executables: we currently provide driver extensions for PostgreSQL, MariaDB, Microsoft SQL Server and H2.

Environment variable: QUARKUS_HIBERNATE_ORM_DIALECT

string

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

string

Query related configuration

タイプ

デフォルト

The maximum size of the query plan cache. see #QueryPlanCache#DEFAULT_QUERY_PLAN_MAX_COUNT

Environment variable: QUARKUS_HIBERNATE_ORM_QUERY_QUERY_PLAN_CACHE_MAX_SIZE

int

2048

Default precedence of null values in ORDER BY clauses.

Valid values are: none, first, last.

Environment variable: QUARKUS_HIBERNATE_ORM_QUERY_DEFAULT_NULL_ORDERING

none, first, last

none

Database related configuration

タイプ

デフォルト

The charset of the database. Used for DDL generation and also for the SQL import scripts.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_CHARSET

Charset

UTF-8

Whether Hibernate should quote all identifiers.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_GLOBALLY_QUOTED_IDENTIFIERS

boolean

false

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

string

none

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

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION_CREATE_SCHEMAS

boolean

false

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

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION_HALT_ON_ERROR

boolean

false

The default catalog to use for the database objects.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_DEFAULT_CATALOG

string

The default schema to use for the database objects.

Environment variable: QUARKUS_HIBERNATE_ORM_DATABASE_DEFAULT_SCHEMA

string

JDBC related configuration

タイプ

デフォルト

The time zone pushed to the JDBC driver.

Environment variable: QUARKUS_HIBERNATE_ORM_JDBC_TIMEZONE

string

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

Environment variable: QUARKUS_HIBERNATE_ORM_JDBC_STATEMENT_FETCH_SIZE

int

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

int

Fetching logic configuration

タイプ

デフォルト

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

int

16

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

int

Caching configuration

タイプ

デフォルト

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

Environment variable: QUARKUS_HIBERNATE_ORM_CACHE__CACHE__EXPIRATION_MAX_IDLE

Duration

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

Environment variable: QUARKUS_HIBERNATE_ORM_CACHE__CACHE__MEMORY_OBJECT_COUNT

long

Discriminator related configuration

タイプ

デフォルト

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

boolean

false

Additional named persistence units

タイプ

デフォルト

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATASOURCE

string

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__PACKAGES

list of string

Path to a file containing the SQL statements to execute when Hibernate ORM starts.

The file is retrieved from the classpath resources, so it 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__PERSISTENCE_UNIT_NAME__SQL_LOAD_SCRIPT

list of string

import.sql in DEV, TEST ; no-file otherwise

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__PHYSICAL_NAMING_STRATEGY

string

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__PERSISTENCE_UNIT_NAME__IMPLICIT_NAMING_STRATEGY

string

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__PERSISTENCE_UNIT_NAME__METADATA_BUILDER_CONTRIBUTOR

string

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__PERSISTENCE_UNIT_NAME__MAPPING_FILES

list of string

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

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__PERSISTENCE_UNIT_NAME__SECOND_LEVEL_CACHING_ENABLED

boolean

true

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__PERSISTENCE_UNIT_NAME__MULTITENANT

string

Defines the name of the datasource to use in case of SCHEMA approach. The datasource of the persistence unit will be used if not set.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__MULTITENANT_SCHEMA_DATASOURCE

string

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__PERSISTENCE_UNIT_NAME__VALIDATE_IN_DEV_MODE

boolean

true

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__PERSISTENCE_UNIT_NAME__UNSUPPORTED_PROPERTIES

Map<String,String>

Dialect related configuration

タイプ

デフォルト

Class name of the Hibernate ORM dialect. The complete list of bundled dialects is available in the Hibernate ORM JavaDoc.

Not all the dialects are supported in GraalVM native executables: we currently provide driver extensions for PostgreSQL, MariaDB, Microsoft SQL Server and H2.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DIALECT

string

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

E.g. MyISAM or InnoDB for MySQL.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DIALECT_STORAGE_ENGINE

string

Query related configuration

タイプ

デフォルト

The maximum size of the query plan cache. see #QueryPlanCache#DEFAULT_QUERY_PLAN_MAX_COUNT

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__QUERY_QUERY_PLAN_CACHE_MAX_SIZE

int

2048

Default precedence of null values in ORDER BY clauses.

Valid values are: none, first, last.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__QUERY_DEFAULT_NULL_ORDERING

none, first, last

none

Database related configuration

タイプ

デフォルト

The charset of the database. Used for DDL generation and also for the SQL import scripts.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATABASE_CHARSET

Charset

UTF-8

Whether Hibernate should quote all identifiers.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATABASE_GLOBALLY_QUOTED_IDENTIFIERS

boolean

false

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__PERSISTENCE_UNIT_NAME__DATABASE_GENERATION

string

none

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATABASE_GENERATION_CREATE_SCHEMAS

boolean

false

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATABASE_GENERATION_HALT_ON_ERROR

boolean

false

The default catalog to use for the database objects.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATABASE_DEFAULT_CATALOG

string

The default schema to use for the database objects.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__DATABASE_DEFAULT_SCHEMA

string

JDBC related configuration

タイプ

デフォルト

The time zone pushed to the JDBC driver.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__JDBC_TIMEZONE

string

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__JDBC_STATEMENT_FETCH_SIZE

int

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__PERSISTENCE_UNIT_NAME__JDBC_STATEMENT_BATCH_SIZE

int

Fetching logic configuration

タイプ

デフォルト

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

-1 means batch loading is disabled.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__FETCH_BATCH_SIZE

int

16

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__PERSISTENCE_UNIT_NAME__FETCH_MAX_DEPTH

int

Caching configuration

タイプ

デフォルト

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__CACHE__CACHE__EXPIRATION_MAX_IDLE

Duration

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__CACHE__CACHE__MEMORY_OBJECT_COUNT

long

Discriminator related configuration

タイプ

デフォルト

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__PERSISTENCE_UNIT_NAME__DISCRIMINATOR_IGNORE_EXPLICIT_FOR_JOINED

boolean

false

Database scripts related configuration

タイプ

デフォルト

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__PERSISTENCE_UNIT_NAME__SCRIPTS_GENERATION

string

none

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__SCRIPTS_GENERATION_CREATE_TARGET

string

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__SCRIPTS_GENERATION_DROP_TARGET

string

Logging configuration

タイプ

デフォルト

Show SQL logs and format them nicely. Setting it to true is obviously not recommended in production.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__LOG_SQL

boolean

false

Format the SQL logs if SQL log is enabled

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__LOG_FORMAT_SQL

boolean

true

Whether JDBC warnings should be collected and logged.

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__LOG_JDBC_WARNINGS

boolean

depends on dialect

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

Environment variable: QUARKUS_HIBERNATE_ORM__PERSISTENCE_UNIT_NAME__LOG_QUERIES_SLOWER_THAN_MS

long

Logging configuration

タイプ

デフォルト

Logs SQL bind parameters. Setting it to true is obviously not recommended in production.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_BIND_PARAMETERS

boolean

false

Show SQL logs and format them nicely. Setting it to true is obviously not recommended in production.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_SQL

boolean

false

Format the SQL logs if SQL log is enabled

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_FORMAT_SQL

boolean

true

Whether JDBC warnings should be collected and logged.

Environment variable: QUARKUS_HIBERNATE_ORM_LOG_JDBC_WARNINGS

boolean

depends on dialect

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

long

Database scripts related configuration

タイプ

デフォルト

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

string

none

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

Environment variable: QUARKUS_HIBERNATE_ORM_SCRIPTS_GENERATION_CREATE_TARGET

string

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

Environment variable: QUARKUS_HIBERNATE_ORM_SCRIPTS_GENERATION_DROP_TARGET

string

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

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

数値で始まる期間の値を指定することもできます。この場合、値が数値のみで構成されている場合、コンバーターは値を秒として扱います。そうでない場合は、 PT が暗黙的に値の前に付加され、標準の java.time.Duration 形式が得られます。

persistence.xml への設定と application.propertiesquarkus.hibernate-orm.* のプロパティを使用することを混在させないでください。Quarkusは例外を発生させます。どちらの方法を採用するかを決めてください。

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.dialect=org.hibernate.dialect.H2Dialect
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 users という永続化ユニットを定義します。

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

デフォルトの永続化ユニットは、デフォルトでデフォルトデータソースを使用します。名前付きの永続化ユニットの場合は 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 JPAのアノテーションではなく、 @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;

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

また、 META-INF/persistence.xml を使用して、Hibernate ORM を設定することもできます。これは次のような場合に便利です:

  • 既存コードの移行

  • 比較的複雑な設定をしていて、設定の柔軟性が必要な場合

  • または、昔ながらの方法が好みの場合

persistence.xml がある場合には quarkus.hibernate-orm.* のプロパティは使用できず、 persistence.xml で定義された永続化ユニットのみが考慮されます。

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.PostgreSQL95Dialect"/>

            <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="javax.persistence.schema-generation.database.action" value="drop-and-create"/>

            <property name="javax.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 形式(JPA) または 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アプリケーションを構築するのと同じプロジェクトでエンティティを定義すれば、すべてがうまく動作します。

エンティティが外部のプロジェクトやjarに含まれている場合は、空の 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

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

CLI
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 )。また、様々な環境を記述するために独自のカスタムプロファイル ( stagingprod-us など )を追加することができます。

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

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

ユーザーが application.properties で明示的にオーバーライドすることもできますが (例: %prod.quarkus.hibernate-orm.sql-load-script = import.sql )、prod で誤ってデータベースをオーバーライドしないようにしたいと思いました :)

そういえば、本番ではデータベーススキーマを落とさないようにしましょう!プロパティファイルに以下を追加します。

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/test モードでリロードした後、DB をクリーンにするために %dev.quarkus.flyway.clean-at-start`%test.quarkus.flyway.clean-at-start が設定されます

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

キャッシング

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

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

L2キャッシュを有効にするには、キャッシュしたいエンティティを @javax.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 を参照してください。

数値で始まる期間の値を指定することもできます。この場合、値が数値のみで構成されている場合、コンバーターは値を秒として扱います。そうでない場合は、 PT が暗黙的に値の前に付加され、標準の java.time.Duration 形式が得られます。

キャッシュの制限

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

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

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

しかし、両者は同じコードを共有していますが、Quarkusはいくつかのコンポーネントを自動的に設定し、いくつかの拡張ポイントにカスタム実装をインジェクションしています。

自動ビルド時間の強化

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

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

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

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

自動統合

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

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

コネクションプール

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

L2キャッシュ

キャッシング の項で説明したように、実装を選択する必要はありません。 InfinispanCaffeine の技術をベースにした適切な実装は、Hibernate ORM拡張の推移依存関係に含まれており、ビルド時に自動的に統合されます。

制約事項

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

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

実際には、クラスパスに XML マッピングファイルが重複して存在するのは、非常に特殊なシナリオの場合に限られます。 例えば、2つのJARに META-INF/orm.xml ファイルが含まれている場合(全く同じパスで、異なるJARに含まれている)、マッピングファイルのパス META-INF/orm.xml は、 <code>META-INF/orm.xml</code> ファイルと同じJARにある persistence.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つのステートメントがあります。既存のスクリプトを再利用する場合は、終端文字として「;」を使用するようにスクリプトを変換することを忘れないでください。これは、複数行のステートメントを可能にし、人間が使いやすいフォーマットにするために役立ちます。

シンプルになったHibernate ORM with Panache

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

データソースの設定

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

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

マルチテナンシー

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

Quarkusは現在、 独立したデータベース独立したスキーマのアプローチをサポートしています。

マルチテナンシーの動作を確認するには、 hibernate-orm-multi-tenancy-quickstart クイックスタートをご覧ください。

アプリケーションの記述

まずは /{tenant} エンドポイントを実装してみましょう。下のソースコードを見るとわかるように、これは通常の JAX-RS リソースです:

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.ws.rs.GET;
import javax.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 javax.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にデフォルトの永続化ユニットで使用することを伝えます。

名前付きの永続化ユニット には、 @PersistenceUnitExtension("nameOfYourPU") を使用します。

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

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

OIDCマルチテナンシーも使用していて、OIDCとHibernate ORMの両方のテナントIDが同じで、Vert.xの RoutingContext から抽出する必要がある場合は、OIDCテナントリゾルバからHibernate ORMテナントリゾルバに、 RoutingContext 属性としてテナントIDを渡すことができます。例:

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

@PersistenceUnitExtension
@RequestScoped
public class CustomTenantResolver implements TenantResolver {

    @Inject
    RoutingContext context;
    ...
    @Override
    public String resolveTenantId() {
        // OIDC TenantResolver has already calculated the tenant id and saved it as a RoutingContext `tenantId` attribute:
        return context.get("tenantId");
    }
}

アプリケーションの設定

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

SCHEMAアプローチ

すべてのテナントに同じデータソースを使用し、そのデータソース内に各テナント用のスキーマを作成する必要があります。注意:MariaDB/MySQLのような一部のデータベースは、データベーススキーマをサポートしていません。このような場合には、以下のようなDATABASEアプローチを使用する必要があります。

# Disable generation
quarkus.hibernate-orm.database.generation=none

# Enable SCHEMA approach and use default datasource
quarkus.hibernate-orm.multitenant=SCHEMA
# You could use a non-default datasource by using the following setting
# quarkus.hibernate-orm.multitenant-schema-datasource=other

# The default data source used for all tenant schemas
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus_test
quarkus.datasource.password=quarkus_test
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test

# Enable Flyway configuration to create schemas
quarkus.flyway.schemas=base,mycompany
quarkus.flyway.locations=classpath:schema
quarkus.flyway.migrate-at-start=true

ここでは、設定されたフォルダー 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 が返すのと同じ識別子を持つ名前付きデータソースを作成する必要があります。

# Disable generation
quarkus.hibernate-orm.database.generation=none

# Enable DATABASE approach
quarkus.hibernate-orm.multitenant=DATABASE

# Default tenant 'base'
quarkus.datasource.base.db-kind=postgresql
quarkus.datasource.base.username=quarkus_test
quarkus.datasource.base.password=quarkus_test
quarkus.datasource.base.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test

# Tenant 'mycompany'
quarkus.datasource.mycompany.db-kind=postgresql
quarkus.datasource.mycompany.username=mycompany
quarkus.datasource.mycompany.password=mycompany
quarkus.datasource.mycompany.jdbc.url=jdbc:postgresql://localhost:5433/mycompany

# Flyway configuration for the default datasource
quarkus.flyway.locations=classpath:database/default
quarkus.flyway.migrate-at-start=true

# Flyway configuration for the mycompany datasource
quarkus.flyway.mycompany.locations=classpath:database/mycompany
quarkus.flyway.mycompany.migrate-at-start=true

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

デフォルトスキーマ ( src/main/resources/database/default/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 schema (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');

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

サポートするさまざまなテナントに対してより動的な設定が必要で、設定ファイルに複数のエントリを残したくない場合は、 io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver インターフェースを使用して接続を取得するための独自のロジックを実装することができます。このインターフェースを実装するアプリケーションスコープのBeanを作成し、 @PersistenceUnitExtension (または 名前付き永続化ユニットの場合は @PersistenceUnitExtension("nameOfYourPU") )アノテーションを付けることで、現在のQuarkusのデフォルトの実装である io.quarkus.hibernate.orm.runtime.tenant.DataSourceTenantConnectionResolver を置き換えることができます。カスタムコネクションリゾルバを使用すると、例えばデータベースからテナント情報を読みとった情報に基づいて実行時にテナントごとに接続を作成することができます。

インターセプター

org.hibernate.InterceptorSessionFactory に割り当てるには、適切な修飾子を持つ CDI Bean を定義するだけです:

@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にデフォルトの永続化ユニットで使用されるように伝えます。

名前付きの永続化ユニット には @PersistenceUnitExtension("nameOfYourPU") を使用する

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

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

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

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