Hibernate ORMとJakarta Persistenceの使用
Hibernate ORMは、Jakarta Persistence(旧称JPA)のデファクトスタンダード実装であり、Object Relational Mapperの完全な実装を提供します。Quarkusで見事に機能します。
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone -b development https://github.com/quarkusio/quarkus-quickstarts.git 、 アーカイブ をダウンロードします。
ソリューションは 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 ドライバーエクステンション。以下のオプションを使用できます。
-
quarkus-jdbc-db2for IBM Db2 -
H2 のための
quarkus-jdbc-h2 -
MariaDB のための
quarkus-jdbc-mariadb -
Microsoft SQL Server のための
quarkus-jdbc-mssql -
MySQL のための
quarkus-jdbc-mysql -
Oracle Database のための
quarkus-jdbc-oracle -
PostgreSQL のための
quarkus-jdbc-postgresql
-
例えば
<!-- 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>
// Hibernate ORM specific dependencies
implementation("io.quarkus:quarkus-hibernate-orm")
// JDBC driver dependencies
implementation("io.quarkus:quarkus-jdbc-postgresql")
persistent オブジェクトに @Entity アノテーションを付けてから、 application.properties で関連する設定プロパティーを追加します。
application.propertiesquarkus.datasource.db-kind = postgresql (1)
%prod.quarkus.datasource.username = hibernate
%prod.quarkus.datasource.password = hibernate
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/hibernate_db
%prod.quarkus.hibernate-orm.schema-management.strategy=create (2)
| 1 | Configure the datasource for production, relying on Dev Services for connection information in tests / dev mode. |
| 2 | Configure Hibernate ORM to create the schema on startup in production, which is useful for experimentation, but rely on convenient defaults in tests / dev mode. |
Note that configuration properties for the Hibernate ORM Quarkus extension are not the same ones as in your typical Hibernate ORM configuration file. They will often map to Hibernate ORM configuration properties but could have different names and don’t necessarily map 1:1 to each other.
また、Quarkusは多くのHibernate ORMの設定を自動的に設定し、多くの場合、より現代的なデフォルト値を使用します。
application.properties で設定可能な項目のリストについては、 Hibernate ORM の設定リファレンス を参照してください。
Hibernate ORM エクステンションがプロジェクトの依存関係の中に入っていればQuarkus の datasource の設定に基づいて EntityManagerFactory が作成されます。
ダイアレクトはデータソースに基づいて自動的に選択および設定されます。 configure it to more precisely match your database (データベースにより正確に一致するように設定) することを推奨します。
その後、 EntityManager をうまくインジェクションすることができます:
@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
@GeneratedValue
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 ダイアレクト は明示的に設定する必要はありません。
Quarkus defaults to the latest, or close to latest, database version:
-
IBM Db2 12.1
-
MariaDB 11.4
-
Microsoft SQL Server 16
-
MySQL 8.4
-
Oracle Database 23
-
PostgreSQL 16
These defaults enable all available features and best performance when using these versions. They also match the Dev Services container versions.
If you intend to connect to an older database version, you must set the db-version explicitly to be lower than or equal to your actual database version:
application.properties with an explicit (older) db-versionquarkus.datasource.db-kind = postgresql
quarkus.datasource.db-version = 17.0 (1)
%prod.quarkus.datasource.username = hibernate
%prod.quarkus.datasource.password = hibernate
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/hibernate_db
| 1 | データベースのバージョンを設定します。Hibernate ORM dialectはそのバージョンをターゲットにします。 |
|
As described above, the version can either be set explicitly via a This is a safeguard: for databases older than what is configured, Hibernate ORM may generate SQL that is invalid which would lead to runtime exceptions. If the database cannot be reached, a warning will be logged but startup will proceed. If you know the database won’t be reachable on startup, consider configuring offline startup, which will automatically disable the check and warning. As a last resort, you can disable the version check completely
using |
その他のデータベース
データベースに対応するQuarkusエクステンションモジュールがない 場合や、何らかの理由でデフォルトがニーズに合わない場合は、明示的に Hibernate ORMダイアレクト を設定する必要があります:
dialect を明示した application.propertiesquarkus.datasource.db-kind = postgresql
quarkus.hibernate-orm.dialect=Cockroach (1)
%prod.quarkus.datasource.username = hibernate
%prod.quarkus.datasource.password = hibernate
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:26257/hibernate_db
| 1 | Hibernate ORM dialectを設定します。
組み込みダイアレクトの場合、指定できる値は ダイアレクトの公式リスト
にある名前のいずれかで、 サードパーティーのダイアレクトの場合、期待される値は完全修飾クラス名です。
たとえば |
|
この場合、JDBCドライバやHibernate ORM dialectがGraalVMネイティブ実行可能ファイルでは正しく動作しない可能性があることに留意してください。 |
supported databases と同様に、 Hibernate ORM を最大限に活用するために、DB バージョンを明示的に設定できます。
dialect と db-version を明示した application.propertiesquarkus.datasource.db-kind = postgresql
quarkus.datasource.db-version = 25.4 (1)
quarkus.hibernate-orm.dialect=Cockroach (2)
%prod.quarkus.datasource.username = hibernate
%prod.quarkus.datasource.password = hibernate
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:26257/hibernate_db
| 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のセットアップに必要な値を推測し、デフォルトのデータソースを使用するようにします。
Hibernate ORM の設定リファレンス にリストされている設定プロパティーを使用すると、このようなデフォルト値を上書きしたり、さまざまな側面をカスタマイズおよび調整したりできます。
|
クラスパスに無視したい
|
複数の永続性ユニット
複数の永続化ユニットの設定
Quarkusの設定プロパティーを使用して、複数の永続化ユニットを定義することができます。
quarkus.hibernate-orm. 名前空間のルートにあるプロパティで、デフォルトの永続化ユニットを定義します。例えば、次のスニペットではデフォルトのデータソースとデフォルトの永続化ユニットを定義しています:
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1
quarkus.hibernate-orm.schema-management.strategy=validate
マップをベースにした方法で名前付きの永続化ユニットを定義することができます:
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".datasource=users (3)
quarkus.hibernate-orm."users".packages=org.acme.model.user (4)
quarkus.hibernate-orm."inventory".datasource=inventory (5)
quarkus.hibernate-orm."inventory".packages=org.acme.model.inventory
| 1 | users という名前のデータソースを定義します。 |
| 2 | inventory という名前のデータソースを定義します。 |
| 3 | users データソースを指す users という名前の永続化ユニットを定義します。 |
| 4 | この設定プロパティは重要ですが、説明は少し後になります。 |
| 5 | users という永続化ユニットを定義します。 |
|
デフォルトデータソースと名前付きデータソースを混在させることも、どちらか一方だけにすることもできます。 |
|
デフォルトの永続化ユニットは、デフォルトでデフォルトデータソースを使用します。名前付きの永続化ユニットの場合は 複数の永続化ユニットが同じデータソースを使用することもできます。 |
モデルクラスを永続化ユニットにアタッチする
モデルクラスを永続化ユニットにアタッチする方法は2つあり、混在してはいけません。
-
packages設定プロパティーを使用します。 -
@io.quarkus.hibernate.orm.PersistenceUnitパッケージレベルのアノテーションを使用します。
両方が混在している場合はアノテーションが無視され、 packages の設定プロパティのみが考慮されます。
packages 設定プロパティは簡単です:
quarkus.hibernate-orm.packages=org.acme.model.defaultpu
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.shared と org.acme.model.user パッケージの下にあるすべてのモデル・クラスは、 users 永続化ユニットにアタッチされます。
モデルクラスを複数の永続化ユニットにアタッチすることもサポートされます。
|
モデルクラスは与えられた永続化ユニットに一貫して追加される必要があります。つまり、与えられたエンティティのすべての依存するモデルクラス( |
|
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 アノテーションを使用することに注意してください。 |
|
モデルクラスの |
設定プロパティで行うのと同様で、アノテーションのつけられたパッケージだけでなく、そのすべてのサブパッケージも入れていることに注意してください。
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;
EntityManager と EntityManagerFactory に加えて、Quarkus は以下の JPA/Hibernate コンポーネントの注入もサポートしています。
@Inject
CriteriaBuilder criteriaBuilder;
@Inject
HibernateCriteriaBuilder hibernateCriteriaBuilder;
@Inject
Metamodel metamodel;
@Inject
jakarta.persistence.Cache cache;
@Inject
org.hibernate.Cache cache;
@Inject
jakarta.persistence.PersistenceUnitUtil persistenceUnitUtil;
@Inject
jakarta.persistence.SchemaManager schemaManager;
@Inject
org.hibernate.relational.SchemaManager schemaManager;
これらのコンポーネントは、特定の永続化ユニット修飾子を使用して注入することもできます。
@Inject
@PersistenceUnit("users")
CriteriaBuilder criteriaBuilder;
コンバーターとエンティティーリスナーのプラグイン
Hibernate ORM 用の Quarkus エクステンションは、 属性コンバーター と エンティティーリスナー の Hibernate ORM への注入をサポートしています。
通常の Hibernate ORM と同じように使用し (上記のリンク先ドキュメントを参照)、コンバーター/リスナーの実装内で必要に応じて CDI 機能 ( @Inject 、 @PostConstruct 、 @PreDestroy など) を利用してください。
CDI スコープが指定されていない場合、コンバーター/リスナーは @Dependent であるかのように振る舞い、使用される永続化ユニットごとに 1 回インスタンス化されます。
コンバーター/リスナーのクラスに @ApplicationScoped などのアノテーションを付けることで、CDI スコープを強制できます。
非常に特殊なシナリオで、CDI アノテーション ( @Inject など) を使用しているにもかかわらず、コンバーター/リスナーでの CDI の使用を抑制する必要がある場合は、 @Vetoed を付与してください。その場合、クラスは Hibernate ORM によってデフォルトコンストラクターを介してインスタンス化されます。
その他のカスタムコンポーネントのプラグイン
Hibernate ORM 用の Quarkus エクステンションは、 @PersistenceUnitExtension アノテーションが付いたコンポーネントを Hibernate Search に自動的に注入します。
このアノテーションは、オプションで @PersistenceUnitExtension(name = "nameOfYourPU") を使用して特定の永続化ユニットをターゲットにできます。
この機能は、次のコンポーネントタイプで使用できます。
org.hibernate.Interceptor-
インターセプター を参照してください。
org.hibernate.resource.jdbc.spi.StatementInspector-
ステートメントインスペクター を参照してください。
org.hibernate.type.format.FormatMapper-
JSON/XML シリアル化/デシリアル化のカスタマイズ を参照してください。
io.quarkus.hibernate.orm.runtime.tenant.TenantResolver-
マルチテナンシー を参照してください。
io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver-
テナント接続をプログラムで解決 を参照してください。
org.hibernate.boot.model.FunctionContributor-
カスタム関数、型、およびマッピング を参照してください。
org.hibernate.boot.model.TypeContributor-
カスタム関数、型、およびマッピング を参照してください。
永続化ユニットのアクティブ化/非アクティブ化
永続化ユニットがビルド時に設定され、エンティティータイプまたは アクティブなデータソース が割り当てられている場合、その永続化ユニットはデフォルトでアクティブになります。Quarkus は、アプリケーションの起動時に対応する Hibernate ORM SessionFactory を開始します。
実行時に永続化ユニットを非アクティブ化するには、 quarkus.hibernate-orm[.optional name].active を false に設定します。
永続化ユニットがアクティブでない場合は、以下のようになります。
-
SessionFactoryはアプリケーションの起動中に開始されません。 -
@Inject SessionFactory sfや@Inject Session sessionなど、永続化ユニットに関連する静的 CDI 注入ポイントは、アプリケーションの起動に失敗する原因となります。 -
CDI.getBeanContainer()、Arc.instance()、または注入されたInstance<Session>などを通じた永続化ユニットの動的な取得は、例外がスローされる原因となります。 -
永続化ユニットを消費する他の Quarkus エクステンションが、アプリケーションの起動を失敗させる可能性があります。
この場合、それらの他のエクステンションも非アクティブ化する必要があります。
これは特に、アプリケーションが 実行時に事前に決められたデータソースのセットの中から 1 つを使用 できるようにしたい場合に便利です。
例えば、次のような設定です:
quarkus.hibernate-orm."pg".packages=org.acme.model.shared
quarkus.hibernate-orm."pg".datasource=pg
quarkus.hibernate-orm."pg".active=false
quarkus.datasource."pg".db-kind=h2
quarkus.datasource."pg".active=false
%prod.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".active=false
quarkus.datasource."oracle".db-kind=oracle
quarkus.datasource."oracle".active=false
%prod.quarkus.datasource."oracle".jdbc.url=jdbc:oracle:///your_database
quarkus.hibernate-orm."pg".active=true と quarkus.datasource."pg".active=true を実行時に 設定 すると、
PostgreSQL の永続化ユニットとデータソースのみが利用可能になり、
quarkus.hibernate-orm."oracle".active=true と quarkus.datasource."oracle".active=true を実行時に設定すると、
Oracle の永続化ユニットとデータソースのみが利用可能になります。
|
カスタム設定プロファイル を使用すると、このような設定を簡素化できます。
以下のプロファイル固有の設定を上記の設定に追加することで、
|
このセットアップでは、 アクティブな 永続化ユニットのみにアクセスするように注意してください。これを実現するには、 @Any 修飾子を付けた InjectableInstance<SessionFactory> または InjectableInstance<Session> を注入し、 getActive() を呼び出します。
import io.quarkus.arc.InjectableInstance;
@ApplicationScoped
public class MyConsumer {
@Inject
@Any
InjectableInstance<Session> session;
public void doSomething() {
Session sessionForActivePersistenceUnit = session.getActive();
// ...
}
}
あるいは、デフォルトの永続化ユニットの Bean 用に CDI Bean プロデューサー を定義することもできます。この Bean プロデューサーは現在アクティブな名前付き永続化ユニットにリダイレクトします。これにより、以下に示すように Bean を直接注入できるようになります。
public class MyProducer {
@Inject
@PersistenceUnit("pg")
InjectableInstance<Session> pgSessionBean; (1)
@Inject
@PersistenceUnit("oracle")
InjectableInstance<Session> oracleSessionBean;
@Produces (2)
@ApplicationScoped
public Session session() {
if (pgSessionBean.getHandle().getBean().isActive()) { (3)
return pgSessionBean.get();
} else if (oracleSessionBean.getHandle().getBean().isActive()) { (3)
return oracleSessionBean.get();
} else {
throw new RuntimeException("No active persistence unit!");
}
}
}
@ApplicationScoped
public class MyConsumer {
@Inject
Session session; (4)
public void doSomething() {
// .. just use the injected session ...
}
}
| 1 | Session を直接注入しないでください。非アクティブな Bean を注入すると起動に失敗します。代わりに InjectableInstance<Session> を注入してください。 |
| 2 | デフォルトのセッションを定義する CDI プロデューサーメソッドを宣言します。これは、どの永続化ユニットがアクティブかに応じて、PostgreSQL または Oracle のいずれかを選択します。 |
| 3 | ビーンを取得する前に、ビーンがアクティブかどうかをチェックします。 |
| 4 | 唯一のアクティブな永続化ユニットを注入します。 |
persistence.xml を使用した場合のHibernate ORMのセットアップと設定
Hibernate ORM をセットアップして設定するには、using application.properties が推奨されます。
ただし、代わりに META-INF/persistence.xml ファイルを使用することもできます。
これは主に、既存のコードを Quarkus に移行する場合に役立ちます。
|
クラスパスに無視したい
|
pom.xml の依存関係と Java コードは先の例と同じになります。唯一の違いは META-INF/persistence.xml で Hibernate ORM の設定を行うことだけです:
<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"/>
<!-- Schema generation on startup -->
<property name="jakarta.persistence.schema-generation.database.action" value="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専用、非推奨 )に従ってマッピングファイルを追加することができます:
-
application.propertiesで (ビルド時に)quarkus.hibernate-orm.mapping-filesプロパティーを使用して追加する方法。 -
persistence.xmlの<mapping-file>の要素を使用して。
XMLマッピングファイルは、ビルド時に解析されます。
|
そうしたくない場合は、 |
外部プロジェクトや jar でエンティティーを定義する
QuarkusのHibernate ORMは、エンティティーに対するコンパイル時のバイトコード強化に依存しています。Quarkusアプリケーションを構築するのと同じプロジェクトでエンティティーを定義すれば、すべてがうまく動作します。
エンティティーが外部のプロジェクトやジャーから来ている場合は、空の META-INF/beans.xml ファイルを追加することで、jarがQuarkusアプリケーションライブラリのように扱われるようにすることができます。
これにより、Quarkusは、エンティティーが現在のプロジェクトの内部にあるかのようにインデックスを作成し、強化することができます。
開発モードでのHibernate ORM
During tests and in development mode, Hibernate ORM benefits from datasource Dev Services, making configuration of database connections unnecessary.
The main remaining question is how to initialize that database.
-
1 つ目の選択肢は、
quarkus.hibernate-orm.schema-management.strategy=drop-and-createをimport.sqlと併用することです。That way for every change to your app and in particular to your entities, the database schema will be properly recreated and your data fixture (stored in
import.sql) will be used to repopulate it from scratch.This is best to perfectly control your environment and works magic with Quarkus live reload mode: your entity changes or any change to your
import.sqlis immediately picked up and the schema updated without restarting the application! In fact, this is the default when using Dev Services.You can use a file with a different name than
import.sqlby setting the propertyquarkus.hibernate-orm.sql-load-scriptinapplication.properties. You can also provide a.zipfile in the same way which should contain only the files containing the SQL statements to be executed. -
The second approach is to use
quarkus.hibernate-orm.schema-management.strategy=update.This approach is best when you do many entity changes but still need to work on a copy of the production data or if you want to reproduce a bug that is based on specific database entries.
updateis a best effort from Hibernate ORM and will fail in specific situations including altering your database structure which could lead to data loss. For example if you change structures which violate a foreign key constraint, Hibernate ORM might have to bail out. But for development, these limitations are acceptable. -
The third approach is to use
quarkus.hibernate-orm.schema-management.strategy=none.This approach is best when you are working on a copy of the production data but want to fully control the schema evolution. Or if you use a database schema migration tool like Flyway or Liquibase.
この方法では、エンティティに変更を加える時にデータベーススキーマに確実に適合させる必要があります。また、
validateを使用して、Hibernateにスキーマが期待どおりかを確認させることもできます。
Do not set quarkus.hibernate-orm.schema-management.strategy to drop-and-create or update in your production environment.
|
これらの方法は、Quarkusの設定プロファイルと組み合わせることで非常に強力になります。異なる 設定プロファイルを定義して、環境に応じて異なる動作を選択することができます。これは、現在必要としている開発スタイルに合わせて、Hibernate ORMのプロパティの異なる組み合わせを定義できるという点で素晴らしいことです。
%dev.quarkus.hibernate-orm.schema-management.strategy = drop-and-create
%dev.quarkus.hibernate-orm.sql-load-script = import-dev.sql
%dev-with-data.quarkus.hibernate-orm.schema-management.strategy = update
%dev-with-data.quarkus.hibernate-orm.sql-load-script = no-file
%prod.quarkus.hibernate-orm.schema-management.strategy = none
%prod.quarkus.hibernate-orm.sql-load-script = no-file
カスタムプロファイルを使用して開発モードを開始することができます:
quarkus dev -Dquarkus.profile=dev-with-data
./mvnw quarkus:dev -Dquarkus.profile=dev-with-data
./gradlew --console=plain quarkusDev -Dquarkus.profile=dev-with-data
本番モードでのHibernate ORM
Quarkusにはデフォルトのプロファイルが付属しています ( dev , test と prod )。また、様々な環境を記述するために独自のカスタムプロファイルを追加することができます ( staging , prod-us , など )。
Hibernate ORM Quarkusエクステンションでは、いくつかのデフォルト設定が、開発モードとテストモードで他の環境とは異なるように設定されています。
-
devとtest以外のプロフィールはquarkus.hibernate-orm.sql-load-scriptがno-fileに設定されています。
ユーザーが application.properties で明示的にオーバーライドすることもできますが (例: %prod.quarkus.hibernate-orm.sql-load-script = import.sql )、prod で誤ってデータベースをオーバーライドしないようにしたいと思いました :)
そういえば、本番ではデータベーススキーマを落とさないようにしましょう!プロパティーファイルに以下を追加します。
%prod.quarkus.hibernate-orm.schema-management.strategy = none
%prod.quarkus.hibernate-orm.sql-load-script = no-file
Flyway 統合
スキーマを管理するための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 の設定はすべての環境に適しているとは限りません。
|
エンティティーの変更による増分マイグレーション
最初のマイグレーションが作成された後、Quarkus は更新されたエンティティーモデルからドラフトマイグレーションを派生させることができるため、変更ごとにベースラインを手書きする必要はありません。新しいマイグレーションを作成するには、Dev UI の Flyway ペインにある Generate Migration File ボタンをクリックします。
| 提案されたスクリプトは必ず確認してください。Quarkus はエンティティーからスキーマの変更を推測しますが、ドメイン固有のデータ移動、並行性の考慮事項、および高度なインデックス戦略には依然として人間の判断が必要です。 |
生成されるマイグレーションファイルは以下のパターンに従います。
-
メジャーバージョンは、プロジェクト内に存在する最後のマイグレーションから抽出されます。
-
マイナーバージョンは、生成時の現在のタイムスタンプになります。
オフライン起動
デフォルトでは、Hibernate は起動時にデータベースへの接続を試み、メタデータを取得します。これは、たとえばスキーマの検証や一時テーブルの作成に役立ち、起動プロセスをよりスムーズでユーザーフレンドリーなものにします。
ただし、Kubernetes クラスター内のコンテナーで Quarkus アプリケーションを実行する場合など、特定の環境では、この接続が不可能な場合があります。たとえば、アプリケーションが特定のポッドで実行され、データベースが別のポッドで実行されている場合、起動時にデータベースに到達できない可能性があります。これに対処するために、Quarkus は Hibernate がアプリケーションの起動中にデータベースへの接続をスキップできるようにする「オフライン起動」モードを提供しています。
オフライン起動を使用する場合、アプリケーションが起動する前に、データベーススキーマが正しく作成されていることを確認することが重要です。
データベーススキーマの作成やマイグレーションには、 Flyway 、 Liquibase 、またはカスタムセットアップを利用できますが、当然ながらデータベースにアクセス可能なタイミングで行う必要があります。特に Flyway の migrate-at-start オプションは、データベースに到達できない場合、アプリケーションの起動時に失敗します。
オフライン起動を有効にするには、以下の設定プロパティーを設定します。
quarkus.hibernate-orm.database.start-offline=true
次のような追加のプロパティーを使用して、特定のデータベースに合わせてダイアレクトの動作を微調整することもできます。
quarkus.hibernate-orm."offline".dialect.mariadb.bytes-per-character=1
quarkus.hibernate-orm."offline".dialect.mariadb.no-backslash-escapes=true
quarkus.hibernate-orm."offline".dialect.mariadb.storage-engine=InnoDB (1)
quarkus.hibernate-orm."inventory".dialect.mysql.storage-engine=MyISAM (2)
| 1 | offline 永続化ユニットの MariaDB ダイアレクト用のストレージエンジンを設定します。 |
| 2 | 永続化ユニットごとに異なるストレージエンジンを使用できます。 |
利用可能なプロパティーの詳細については、 Hibernate ORM の設定リファレンス セクションを参照してください。
キャッシング
同じエンティティを頻繁に読み込むアプリケーションでは、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;
// ...
}
クエリのキャッシュ
クエリは、第二レベルのキャッシュの恩恵を受けることもできます。キャッシュされたクエリの結果は即座に呼び出し元に返すことができるので、データベース上でクエリを実行する必要がありません。
最近の変化を反映していない可能性があることを含意しているので注意が必要です。
クエリをキャッシュするには、 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> を実際のリージョン名に置き換えてください)で時間(下記の時間のフォーマットに関する注意を参照)を指定します。
|
領域名にドットが含まれている場合は二重引用符が必須です。次のようになります:
|
Weight-based eviction
For entities with highly variable sizes (e.g., storing JSON data that ranges from a few bytes to megabytes), count-based eviction cannot reliably bound memory usage. In these cases, use weight-based eviction instead:
quarkus.hibernate-orm.cache."org.acme.MyEntity".memory.maximum-weight=104857600
quarkus.hibernate-orm.cache."org.acme.MyEntity".memory.weigher-class=org.acme.MyEntityWeigher
The maximum-weight property sets the total weight limit for the cache region. The weigher-class
property specifies a com.github.benmanes.caffeine.cache.Weigher implementation that assigns a
weight to each cache entry:
import com.github.benmanes.caffeine.cache.Weigher;
public class MyEntityWeigher implements Weigher<Object, Object> {
@Override
public int weigh(Object key, Object value) {
// Estimate memory based on entity data size
return 100; // default weight
}
}
object-count and maximum-weight are mutually exclusive per cache region.
If maximum-weight is set without weigher-class, each entry has a default weight of 1.
|
|
期間の値を書くには、標準の 数字で始まる簡略化した書式を使うこともできます:
その他の場合は、簡略化されたフォーマットが解析のために
|
キャッシングの制限
Quarkusで提供されているキャッシング技術は、現在のところ非常に初歩的で限られています。
Quarkusの開発チームは最初から ある程度の キャッシュ機能があった方が何もないよりは良いと考えました。将来のリリースではより良いキャッシュソリューションが統合されることを期待しています。
|
これらのキャッシュはローカルに保持されているため、他のアプリケーションによって永続ストアに変更が加えられても無効化されたり更新されたりすることはありません。 また、同じアプリケーションの複数のコピーを(Kubernetes/OpenShiftなどのクラスタで)実行している場合、アプリケーションの別々のコピーのキャッシュは同期されません。 これらの理由から、ある種の仮定が成り立つ場合にのみキャッシュを有効にすることが適しています。私たちは、変化しないエンティティ、コレクション、およびクエリのみをキャッシュすることを強く推奨します。あるいは、そのようなエンティティが実際に変更され、古くなった(stale)ものを読み取ったとしても、アプリケーションの期待値に影響を与えないようにする必要があります。 このアドバイスに従うことで、アプリケーションがL2キャッシュから最高のパフォーマンスを引き出し、かつ予期せぬ動作を避けることができます。 不変のデータだけでなく、ある文脈では、可変のデータに対してもキャッシュを有効にすることが許容されるかもしれません。これは、頻繁に読み込まれ、ある程度の陳腐化を許容できるようなエンティティを選択した場合、必要なトレードオフとなり得ます。この「許容される陳腐化の度合い」は、eviction プロパティを設定することで調整できます。しかし、これは推奨されておらず、データに予期せぬ影響を与える可能性があるため、細心の注意を払って行う必要があります。 理想的には、変更可能なデータでキャッシュを有効にするのではなく、クラスタ化されたキャッシュを使用することがより良い解決策です。しかし、現時点では、Quarkusはそのような実装を提供していません:この必要性を知らせれば、チームがこれを考慮することができますので、お気軽にご連絡ください。 |
最後に、 hibernate.cache.use_second_level_cache を false に設定することで、L2キャッシュをグローバルで無効化できます。この設定は、 persistence.xml 設定ファイルで指定する必要があります。
L2キャッシュを無効にすると、すべてのキャッシュアノテーションは無視され、すべてのクエリはキャッシュを無視して実行されます。これは通常、問題を診断する場合にのみ有効です。
Hibernate Envers
Hibernate ORMのEnversエクステンションは、エンティティークラスのための簡単な監査/バージョン管理ソリューションを提供することを目的としています。
Quarkusでは、Enversには専用のQuarkus Extensionがあります。 io.quarkus:quarkus-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/を参照してください。
Hibernate Spatial
Hibernate ORM の Spatial エクステンションは、地理データの保存およびクエリー機能に対する、標準化されたクロスデータベースインターフェースを提供します。
Hibernate Spatial を使用するには、単にプロジェクトに依存関係を追加するだけです。
<!-- Add the Hibernate Spatial module -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-spatial</artifactId>
</dependency>
依存関係のバージョンは Quarkus によって管理されるため、明示的に指定する必要はありません。
Spatial に関するすべての情報は、Hibernate ユーザーガイドに記載されています。 Hibernate ORM Spatial 。
Hibernate Vector
The Vector extension to Hibernate ORM provides support for mathematical vector types, functions, and vector similarity search. It enables storage and querying of vector embeddings (arrays of bytes, floats, or doubles) in databases that support native vector types or arrays. This is commonly used in AI/ML applications to persist and query embeddings generated by machine learning models.
To use Hibernate Vector, add the dependency to your project:
<!-- Add the Hibernate Vector module -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-vector</artifactId>
</dependency>
依存関係のバージョンは Quarkus によって管理されるため、明示的に指定する必要はありません。
To map a vector column, annotate a persistent attribute with one of the various vector @JdbcTypeCode`s (for example, `SqlTypes.VECTOR for a float[] embedding) and specify the vector length with @Array(length = …).
@Entity
public class Document {
@Id
private Long id;
@Column(name = "the_vector")
@JdbcTypeCode(SqlTypes.VECTOR)
@Array(length = 1536)
private float[] theVector;
}
You can find all information about Vector in the Hibernate user guide: Hibernate ORM Vector.
メトリクス
Micrometer は、 Hibernate ORM が実行時に収集するメトリクスを公開できます。 /q/metrics エンドポイントで Hibernate メトリクスの公開を有効にするには、プロジェクトがメトリクスエクステンションに依存していることを確認し、設定プロパティー quarkus.hibernate-orm.metrics.enabled を true に設定してください。
制限事項など知っておくべきこと
Quarkusは使用するライブラリを変更しません。このルールはHibernate ORMにも適用されます。このエクステンションを使用すると、元のライブラリを使用した場合とほとんど同じエクスペリエンスが得られます。
しかし、両者は同じコードを共有していますが、Quarkusはいくつかのコンポーネントを自動的に設定し、いくつかの拡張ポイントにカスタム実装をインジェクションしています。
自動ビルド時間の強化
Hibernate ORMでは、ビルド時に拡張されたエンティティを使用できます。通常、これは必須ではありませんが便利でアプリケーションのパフォーマンスを向上させることができます。
通常は、ビルドスクリプトにHibernate Enhancementプラグインを含める必要がありますが、QuarkusではEnhancementステップがQuarkusアプリケーションのビルドと分析に統合されているため、その必要はありません。
|
Enhancement を使用しているため、エンティティで この制限は将来的に削除される可能性があります。 |
自動統合
- トランザクション・マネージャーの統合
-
これを設定する必要はありません。Quarkusは自動的にNarayana Transaction Managerへの参照をインジェクションします。この依存関係は、Hibernate ORMエクステンションの推移的依存関係として自動的に含まれます。すべての設定はオプションです。詳細は、 Quarkusでのトランザクションの使用を参照してください。
- 接続プール
-
どちらかを選択する必要はありません。上記の例のようにデータソースを設定するだけで、Hibernate ORMがAgroalを使用するように設定されます。このコネクションプールの詳細については、 Quarkus - データソースを参照してください。
- セカンドレベルキャッシュ
-
As explained earlier in the Caching section, you don’t need to pick an implementation. A suitable implementation based on JCache and Caffeine is included as a transitive dependency of the Hibernate ORM extension, and automatically integrated during the build.
制約事項
- クラスパスに重複したファイルがある場合のXMLマッピング
-
XML マッピング ファイルは一意のパスを持つことが期待されます。
実際には、クラスパスに XML マッピングファイルを重複して配置するのは、非常に特殊なシナリオの場合のみです。たとえば、2つのJARに(まったく同じパスで異なるJARにある)
META-INF/orm.xmlファイルが含まれている場合、マッピングファイルのパス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つのステートメントがあります。既存のスクリプトを再利用する場合は、終端文字として「;」を使用するようにスクリプトを変換することを忘れないでください。これは、複数行のステートメントを可能にし、人間が使いやすいフォーマットにするために役立ちます。
Simplified Hibernate ORM with Panache
Hibernate ORM with Panache エクステンションはアクティブレコードスタイルのエンティティ(およびリポジトリ)を提供してHibernate ORMを簡単に使えるようにし、Quarkusでエンティティを簡単に楽しく書けるようにすることに重点を置いています。
データソースの設定
データソースの設定は非常にシンプルですが、技術的にはQuarkus用のAgroal接続プールエクステンションによって実装されているため、別のガイドで説明します。
詳細は Quarkus - データソースをご覧ください。
マルチテナンシー
「マルチテナントという用語は、一般的にソフトウェア開発に適用され、アプリケーションの単一の実行インスタンスが同時に複数のクライアント(テナント)にサービスを提供するアーキテクチャを示す。これは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にデフォルトの永続化ユニットで使用することを伝えます。
名前付きの永続化ユニット には、 |
| 2 | Beanは、テナントの解決が入ってくるリクエストに依存するため @RequestScoped にします。 |
上記の実装ではテナントはリクエストパスから解決されるので、テナントが推測できない場合はデフォルトのテナント識別子が返されます。
|
OIDC マルチテナンシー も使用しており、OIDC と Hibernate ORM のテナント ID が同じ場合は、
以下の例のように
|
アプリケーションの設定
一般的に、Hibernate ORMのデータベース生成機能をマルチテナンシーのセットアップと組み合わせて使用することはできません。そのため、この機能を無効にして、テーブルがスキーマごとに作成されるようにする必要があります。以下のセットアップでは、 Flyway エクステンションを使用してこの目的を達成します。
SCHEMAアプローチ
すべてのテナントに同じデータソースが使用され、そのデータソース内のすべてのテナントに対してスキーマを作成する必要があります。
MariaDBやMySQLなどの一部のデータベースは、デフォルトではデータベーススキーマをサポートしていません。これらの場合、以下のいずれかを行います。
1. スキーマをサポートするように JDBC ドライバーを構成する。
MySQL Connector/J の場合は、 quarkus.datasource.jdbc.additional-jdbc-properties."databaseTerm"=SCHEMA または quarkus.datasource."datasource-name".jdbc.additional-jdbc-properties."databaseTerm"=SCHEMA を使用します。
MariaDB Connector/J の場合は、 quarkus.datasource.jdbc.additional-jdbc-properties."useCatalogTerm"=SCHEMA または quarkus.datasource."datasource-name".jdbc.additional-jdbc-properties."useCatalogTerm"=SCHEMA を使用します。
|
および 2. DATABASE アプローチ にフォールバックする。
quarkus.hibernate-orm.schema-management.strategy=none (1)
quarkus.hibernate-orm.multitenant=SCHEMA (2)
quarkus.datasource.db-kind=postgresql (3)
quarkus.flyway.schemas=base,mycompany (4)
quarkus.flyway.locations=classpath:schema
quarkus.flyway.migrate-at-start=true
%prod.quarkus.datasource.username=quarkus_test
%prod.quarkus.datasource.password=quarkus_test
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test
| 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.fruit_seq INCREMENT BY 50; -- 50 is quarkus default
CREATE TABLE base.fruit
(
id INT,
name VARCHAR(40)
);
INSERT INTO base.fruit(id, name) VALUES (1, 'Cherry');
INSERT INTO base.fruit(id, name) VALUES (2, 'Apple');
INSERT INTO base.fruit(id, name) VALUES (3, 'Banana');
ALTER SEQUENCE base.fruit_seq RESTART WITH 4;
CREATE SEQUENCE mycompany.fruit_seq INCREMENT BY 50; -- 50 is quarkus default
CREATE TABLE mycompany.fruit
(
id INT,
name VARCHAR(40)
);
INSERT INTO mycompany.fruit(id, name) VALUES (1, 'Avocado');
INSERT INTO mycompany.fruit(id, name) VALUES (2, 'Apricots');
INSERT INTO mycompany.fruit(id, name) VALUES (3, 'Blackberries');
ALTER SEQUENCE mycompany.fruit_seq RESTART WITH 4;
データベースアプローチ
すべてのテナントに対して、 TenantResolver が返すのと同じ識別子を持つ名前付きデータソースを作成する必要があります。
|
このアプローチでは、同じ永続化ユニットで使用されるすべてのデータソースが、
同じベンダー (同じ 不一致は検出されず、予期しない動作が発生する可能性があります。 データソースのリストはビルド時に定義されるため、この方法ではテナントの リスト は ビルド時に固定 されます。 実行時にテナントのリストを変更する必要がある場合は、 プログラムでテナント接続を解決する 必要があります。 |
quarkus.hibernate-orm.schema-management.strategy=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.flyway.base.locations=classpath:database/base (5)
quarkus.flyway.base.migrate-at-start=true
%prod.quarkus.datasource.base.username=base
%prod.quarkus.datasource.base.password=base
%prod.quarkus.datasource.base.jdbc.url=jdbc:postgresql://localhost:5432/base
# Tenant 'mycompany'
quarkus.datasource.mycompany.db-kind=postgresql (6)
quarkus.flyway.mycompany.locations=classpath:database/mycompany (7)
quarkus.flyway.mycompany.migrate-at-start=true
%prod.quarkus.datasource.mycompany.username=mycompany
%prod.quarkus.datasource.mycompany.password=mycompany
%prod.quarkus.datasource.mycompany.jdbc.url=jdbc:postgresql://localhost:5433/mycompany
| 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 fruit_seq INCREMENT BY 50; -- 50 is quarkus default
CREATE TABLE fruit
(
id INT,
name VARCHAR(40)
);
INSERT INTO fruit(id, name) VALUES (1, 'Cherry');
INSERT INTO fruit(id, name) VALUES (2, 'Apple');
INSERT INTO fruit(id, name) VALUES (3, 'Banana');
ALTER SEQUENCE fruit_seq RESTART WITH 4;
テナント mycompany のスキーマ (src/main/resources/database/mycompany/V1.0.0__create_fruits.sql):
CREATE SEQUENCE fruit_seq INCREMENT BY 50; -- 50 is quarkus default
CREATE TABLE fruit
(
id INT,
name VARCHAR(40)
);
INSERT INTO fruit(id, name) VALUES (1, 'Avocado');
INSERT INTO fruit(id, name) VALUES (2, 'Apricots');
INSERT INTO fruit(id, name) VALUES (3, 'Blackberries');
ALTER SEQUENCE fruit_seq RESTART WITH 4;
識別子のアプローチ
デフォルトのデータソースがすべてのテナントに使用されます。 @TenantId でアノテーションされたフィールドを定義しているすべてのエンティティには、そのフィールドが自動的に入力され、クエリで自動的にフィルタリングされます。
quarkus.hibernate-orm.multitenant=DISCRIMINATOR (1)
quarkus.datasource.db-kind=postgresql (2)
%prod.quarkus.datasource.username=quarkus_test
%prod.quarkus.datasource.password=quarkus_test
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test
| 1 | discriminator マルチテナンシーを有効にします。 |
| 2 | データソースを設定します。 |
テナント接続をプログラムで解決
サポートするさまざまなテナントに対してより動的な設定が必要で、設定ファイルに複数のエントリを残したくない場合は、 io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver インターフェースを使用して接続を取得するための独自のロジックを実装することができます。このインターフェースを実装するアプリケーションスコープのBeanを作成し、 @PersistenceUnitExtension (または 名前付き永続化ユニットの場合は @PersistenceUnitExtension("nameOfYourPU") )アノテーションを付けることで、現在のQuarkusのデフォルトの実装である io.quarkus.hibernate.orm.runtime.tenant.DataSourceTenantConnectionResolver を置き換えることができます。カスタムコネクションリゾルバを使用すると、例えばデータベースからテナント情報を読みとった情報に基づいて実行時にテナントごとに接続を作成することができます。
|
自動統合 は、プログラムで作成された |
ここでは、Quarkusの標準的なテクノロジーであるプーリング用のAgroalとトランザクション用のNarayanaを使用した、 TenantConnectionResolver の実装例を紹介します:
@ApplicationScoped
@PersistenceUnitExtension
public class ExampleTenantConnectionResolver implements TenantConnectionResolver {
private final jakarta.transaction.TransactionManager transactionManager;
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
public ExampleTenantConnectionResolver(
TransactionManager transactionManager,
TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
this.transactionManager = transactionManager;
this.transactionSynchronizationRegistry = transactionSynchronizationRegistry;
}
@Override
public ConnectionProvider resolve(String tenantId) {
// Use your own ConnectionProvider implementation here
return new YourOwnCustomConnectionProviderImpl(createDatasource(tenantId));
}
private AgroalDataSource createDatasource(String tenantId) {
try {
final var txIntegration = new NarayanaTransactionIntegration(
transactionManager, transactionSynchronizationRegistry, null, false, null);
// Fetch JDBC URL, username, password & other values from a per-tenant dynamic source
final var dataSourceConfig = new AgroalDataSourceConfigurationSupplier()
.connectionPoolConfiguration(pc -> pc.initialSize(2)
.maxSize(10)
.minSize(2)
.maxLifetime(Duration.of(5, ChronoUnit.MINUTES))
.acquisitionTimeout(Duration.of(30, ChronoUnit.SECONDS))
.transactionIntegration(txIntegration)
.connectionFactoryConfiguration(
cf -> cf.jdbcUrl("jdbc:postgresql://postgres:5432/" + tenantId)
.credential(new NamePrincipal(username))
.credential(new SimplePassword(password))));
return AgroalDataSource.from(dataSourceConfig.get());
} catch (SQLException ex) {
throw new IllegalStateException(
"Failed to create a new data source based on the existing datasource configuration", ex);
}
}
}
カスタム関数、型、およびマッピング
Hibernate ORM でカスタム SQL 関数や型を登録するには、標準の Hibernate インターフェースを実装できます。
-
org.hibernate.boot.model.FunctionContributor -
org.hibernate.boot.model.TypeContributor
これらのインターフェースのいずれかを実装したアプリケーションスコープの Bean を作成し、 @PersistenceUnitExtension (名前付き永続化ユニットの場合は @PersistenceUnitExtension("nameOfYourPU") ) アノテーションを付与すると、対応する永続化ユニットに自動的に登録されます。
カスタム関数コントリビューターの例です。
import java.util.List;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.ReturnableType;
import org.hibernate.sql.ast.tree.expression.SqlAstNodeRenderingMode;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import io.quarkus.hibernate.orm.PersistenceUnitExtension;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
@PersistenceUnitExtension
public class CustomFunctionContributor implements FunctionContributor {
@Override
public void contributeFunctions(FunctionContributions functionContributions) {
functionContributions.getFunctionRegistry().register(
"addHardcodedSuffix",
new HardcodedSuffixFunction(
functionContributions.getTypeConfiguration(), "_some_suffix"));
}
private static final class HardcodedSuffixFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
private final String suffix;
private HardcodedSuffixFunction(TypeConfiguration typeConfiguration, String suffix) {
super("addHardcodedSuffix",
StandardArgumentsValidators.exactly(1),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve(StandardBasicTypes.STRING)),
StandardFunctionArgumentTypeResolvers.impliedOrInvariant(typeConfiguration, StandardBasicTypes.STRING)
);
this.suffix = suffix;
}
@Override
public void render(SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments, ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql('(');
walker.render(sqlAstArguments.get(0), SqlAstNodeRenderingMode.DEFAULT);
sqlAppender.appendSql(" || '" + suffix + "')");
}
}
}
カスタム UserType (例: Boolean を "Y"/"N" にマッピングする) を登録する、カスタムタイプコントリビューターの例です。
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.usertype.UserType;
import io.quarkus.hibernate.orm.PersistenceUnitExtension;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
@PersistenceUnitExtension
public class CustomTypeContributor implements TypeContributor {
@Override
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
// Registers the custom type so it can be used via @Type(value = BooleanYesNoType.class) on your entity property
typeContributions.getTypeConfiguration()
.getBasicTypeRegistry()
.register(new BooleanYesNoType(), "boolean_yes_no");
}
public static final class BooleanYesNoType implements UserType<Boolean> {
@Override
public int getSqlType() {
return SqlTypes.VARCHAR;
}
@Override
public Class<Boolean> returnedClass() {
return Boolean.class;
}
@Override
public Boolean nullSafeGet(ResultSet rs, int position, WrapperOptions options) throws SQLException {
String value = rs.getString(position);
if (value == null) {
return null;
}
return "Y".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value);
}
@Override
public void nullSafeSet(PreparedStatement st, Boolean value, int position, WrapperOptions options) throws SQLException {
if (value == null) {
st.setNull(position, SqlTypes.VARCHAR);
} else {
st.setString(position, value ? "Y" : "N");
}
}
@Override
public Boolean deepCopy(Boolean value) {
return value;
}
@Override
public boolean isMutable() {
return false;
}
}
}
インターセプター
適切な修飾子を持つ CDI Bean を定義するだけで、 SessionFactory に org.hibernate.Interceptorを割り当てることができます。
@PersistenceUnitExtension (1)
public static class MyInterceptor implements Interceptor, Serializable { (2)
@Override
public boolean onLoad(Object entity, Object id, Object[] state, (3)
String[] propertyNames, Type[] types) {
// ...
return false;
}
}
| 1 | インターセプターの実装に @PersistenceUnitExtension の修飾子を付けて、Quarkusにデフォルトの永続化ユニットで使用されるように伝えます。
名前付きの永続化ユニット には |
| 2 | 必要に応じて org.hibernate.Interceptor のメソッドを実装します。 |
|
デフォルトでは、 エンティティマネージャーごとに1つのインターセプターのインスタンスを作成するには、Beanに |
|
Hibernate ORM 自体の制限により、 |
ステートメントインスペクター
適切な修飾子を持つCDI Beanを定義するだけで、 SessionFactory に org.hibernate.engine.jdbc.spi.StatementInspector を割り当てることができます:
@PersistenceUnitExtension (1)
public class MyStatementInspector implements StatementInspector { (2)
@Override
public String inspect(String sql) {
// ...
return sql;
}
}
| 1 | ステートメントインスペクターの実装に @PersistenceUnitExtension という修飾子を付けて、Quarkus にデフォルトの永続化ユニットで使用するように指示します。
名前付きの永続化ユニット には |
| 2 | org.hibernate.engine.jdbc.spi.StatementInspector を実装してください。 |
JSON/XML シリアル化/デシリアル化のカスタマイズ
By default, Quarkus will delegate to Hibernate ORM for configuring the appropriate format mappers.
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 に知らせます。
|
||
| 2 | フォーマットマッパーの実装に @PersistenceUnitExtension 修飾子のアノテーションを付与し、
これがデフォルトの永続化ユニットで使用されるべきものであることを Quarkus に知らせます。
名前付きの永続化ユニット には |
||
| 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 に知らせます。
名前付きの永続化ユニット には |
| 3 | org.hibernate.type.format.FormatMapper を実装します。 |
|
フォーマットマッパーには、 同じ永続化ユニットに複数の JSON (または XML) 形式マッパーを登録すると、あいまいさのために例外が発生します。 |
バリデーションモードと Hibernate Validator の統合
Hibernate ORM への Hibernate Validator の統合により、以下の機能が利用可能になります。
-
ライフサイクルイベント時のエンティティーバリデーションの実行
-
エンティティーからの制約情報を DDL に適用
Quarkus の観点からは、これは quarkus.hibernate-orm.validation.mode 設定プロパティー によって制御されます。利用可能なバリデーションモードは以下の通りです。
-
auto— デフォルトのオプション。アプリケーションがquarkus-hibernate-validatorを使用している場合はcallbackとddlが同時に有効である場合と同様に動作し、そうでない場合はnoneとして動作します。 -
callback— Hibernate Validator がライフサイクルイベントのバリデーションを実行します。 -
ddl— Hibernate Validator の制約が DDL 操作 で考慮されます。 -
none— Hibernate Validator の統合が無効になります。
対応する Jakarta Validation ルールを持つすべての制約は callback バリデーション中に適用されますが、 ddl モードでは、DDL に影響を与えるために制約のサブセットのみが使用されます。Hibernate Validator のドキュメントに、 利用可能な制約のリスト とそれらが DDL 生成に与える影響が記載されています。
プロパティーにいくつかの制約が適用された単純なエンティティーを考えてみましょう。
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity
public class MyEntity {
@Id
@GeneratedValue
public long id;
@NotNull
@NotEmpty
@Size(max = 50)
public String name;
public String value;
}
ddl モードを有効にした場合、生成されるスキーマには以下の制約が含まれることが期待されます。
create table myentity
(
id bigint not null primary key,
name varchar(50) not null, (1)
value varchar(255), (2)
);
| 1 | name カラムには @NotNull 制約があるため not null 制約が付き、値の長さは @Size(max=50) 制約により 50 に制限されます。 |
| 2 | エンティティーの value プロパティーには制約がないため、DDL に追加の制約は含まれず、255 という長さ制限はデフォルトの jakarta.persistence.Column#length() に由来します。 |
callback モードでは、 jakarta.validation.ConstraintViolationException がスローされることを期待してください。
try {
MyEntity entity = new MyEntity();
entity.setName(veryLongName);
em.persist(entity);
em.flush();
} catch (ConstraintViolationException exception) {
// handle the constraint violations somehow
}
Quarkus には jakarta.validation.ConstraintViolationException 用の組み込み例外マッパーがあるため、これらの例外を明示的に処理することは冗長になる可能性があります。詳細は Hibernate Validator ガイドの REST エンドポイントのバリデーション セクションを参照してください。
静的メタモデルと Jakarta Data
Both static metamodel and Jakarta Data capabilities of Hibernate ORM are available in Quarkus
through the quarkus-data-processor annotation processor. Since it is an annotation processor,
you must configure it accordingly in your build tool:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- This setting is required for the annotation processor dependencies to be managed by Quarkus.
More information is available in Maven compiler plugin documentation:
https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#annotationProcessorPathsUseDepMgmt -->
<annotationProcessorPathsUseDepMgmt>true</annotationProcessorPathsUseDepMgmt>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-data-processor</artifactId>
<!-- Note, no artifact version is required, it's managed by Quarkus. -->
</path>
<!-- other processors that may be required by your app -->
</annotationProcessorPaths>
<!-- Other compiler plugin configuration options -->
</configuration>
</plugin>
// Enforce the version management of your annotation processor dependencies,
// so that there's no need to define an explicit version of the quarkus-data-processor
annotationProcessor enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
annotationProcessor 'io.quarkus:quarkus-data-processor'
静的メタモデル
生成された静的メタモデルを使用すると、型安全な方法でクエリーを構築できます。シンプルなエンティティを考えてみましょう。
@Entity
public class MyEntity {
@Id
@GeneratedValue
public Integer id;
@Column(unique = true)
public String name;
}
静的メタモデルを使用して作成されたクエリーは、次のようになります。
var builder = session.getCriteriaBuilder();
var criteria = builder.createQuery(MyEntity.class);
var e = criteria.from(MyEntity_.class);
criteria.where(e.get(MyEntity_.name).equalTo(name));
var query = session.createQuery(criteria);
var result = query.list();
静的メタモデルの詳細については、 Jakarta Persistence 仕様 を参照してください。
Jakarta Data
Jakarta Data requires, besides having the quarkus-data-processor annotation processor in place, one extra dependency to be added:
<dependency>
<groupId>jakarta.data</groupId>
<artifactId>jakarta.data-api</artifactId>
</dependency>
implementation 'jakarta.data:jakarta.data-api'
この依存関係を追加し、アノテーションプロセッサーを配置すると、次のようにリポジトリーを簡単に作成できます。
@Repository
public interface MyRepository extends CrudRepository<MyEntity, Integer> { (1)
@Query("select e from MyEntity e where e.name like :name") (2)
List<MyEntity> findByName(String name);
@Delete (3)
void delete(String name);
}
| 1 | CRUD 操作のボイラープレートな定義をスキップするために、利用可能なインターフェース (例: CrudRepository や BasicRepository) のいずれかを使用できます。 |
| 2 | パラメーター付きのカスタムクエリーの追加は、 @Query アノテーションにクエリー文字列を提供するのと同様に簡単です。 |
| 3 | Jakarta Data インターフェースの基本的な CRUD 操作で不十分な場合は、いつでもカスタム操作を追加できます。この例では、名前で MyEntity を削除する削除操作です。 |
そして、リポジトリーは他の Bean と同様に使用できます。
public class MyEntityResource {
@Inject
MyRepository repository;
@POST
@Transactional
public void create(MyEntity entity) {
repository.insert(entity);
}
// ...
}
|
デフォルト以外の永続化ユニットを操作する場合は、リポジトリーアノテーションの
|
他にどのような機能があるかについては、対応する Hibernate Data Repositories および Jakarta Data ガイドを参照してください。
Jakarta Data リポジトリーのセキュア化
Quarkus Security は、セキュリティーアノテーションを使用して Jakarta Data リポジトリーを保護するための初期サポートを提供します。
@Repository
public interface MyRepository extends CrudRepository<MyEntity, Integer> {
@RolesAllowed("admin")
@Delete
void delete(String name);
}
@Authenticated
@Repository
public interface MyRepository extends CrudRepository<MyEntity, Integer> {
@Delete
void delete(String name);
}
|
上記の例では、 |
|
現在、型変数やワイルドカードを使用する汎用インターフェースメソッドは、標準のセキュリティーアノテーションでは確実には保護できません。したがって、そのようなメソッドを保護しようとするのではなく、以下に説明する 2 つの代替案のいずれかを使用する必要があります。 型変数を使用した汎用メソッドを持つリポジトリーの例
代替案 1: REST レイヤーの呼び出し元メソッドにセキュリティーアノテーションを適用する。
代替案 2: リポジトリーインターフェースの型変数
|
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:
Environment variable: Show more |
boolean |
|
||
If Environment variable: Show more |
boolean |
|
||
Whether statistics collection is enabled. If 'metrics.enabled' is true, then the default here is considered true, otherwise the default is false. Environment variable: 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 ( Environment variable: Show more |
boolean |
|||
Whether metrics are published if a metrics extension is enabled. Environment variable: Show more |
boolean |
|
||
Allow hql queries in the Dev UI page Environment variable: Show more |
boolean |
|
||
Enable or disable access to a Hibernate ORM Environment variable: Show more |
boolean |
|
||
The name of the datasource which this persistence unit uses. If undefined, it will use the default datasource. Environment variable: Show more |
string |
|||
The packages in which the entities affected to this persistence unit are located. Environment variable: Show more |
文字列のリスト |
|||
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. The default value for this setting differs depending on the Quarkus launch mode:
If you need different SQL statements between dev mode, test ( application.properties
Environment variable: Show more |
文字列のリスト |
|
||
Pluggable strategy contract for applying physical naming rules for database object names. Class name of the Hibernate PhysicalNamingStrategy implementation Environment variable: Show more |
string |
|||
Pluggable strategy for applying implicit naming rules when an explicit name is not given. Class name of the Hibernate ImplicitNamingStrategy implementation Environment variable: Show more |
string |
|||
XML files to configure the entity mapping, e.g. Defaults to Environment variable: Show more |
文字列のリスト |
|
||
Identifiers can be quoted using one of the available strategies. Set to Environment variable: Show more |
|
|
||
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: Show more |
boolean |
|
||
Defines how the Bean Validation integration behaves. Environment variable: Show more |
list of |
|
||
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: Show more |
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: Show more |
boolean |
|
||
Whether this persistence unit should be active at runtime. Note that if Hibernate ORM is disabled (i.e. Environment variable: Show more |
boolean |
|
||
Properties that should be passed on directly to Hibernate ORM.
Use the full configuration property key here,
for instance
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: Show more |
Map<String,String> |
|||
This property is deprecated since Whether Hibernate ORM is working in blocking mode. Hibernate ORM’s blocking Environment variable: Show more |
boolean |
|
||
This property is deprecated: Use The size of the batches used when loading entities and collections.
Environment variable: Show more |
int |
|
||
This property is deprecated: Use The maximum depth of outer join fetch tree for single-ended associations (one-to-one, many-to-one). A Environment variable: Show more |
int |
|||
This property is deprecated: Use Class name of a custom
Environment variable: Show more |
string |
|||
This property is deprecated since Enables the Bean Validation integration. Environment variable: Show more |
boolean |
|
||
This property is deprecated: Use 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: Show more |
string |
|||
型 |
デフォルト |
|||
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:
Environment variable: Show more |
|
|
||
The charset of the database. Used for DDL generation and also for the SQL import scripts. Environment variable: Show more |
|
|||
The default catalog to use for the database objects. Environment variable: Show more |
string |
|||
The default schema to use for the database objects. Environment variable: Show more |
string |
|||
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 This should be set to Environment variable: Show more |
boolean |
|
||
Instructs Hibernate ORM to avoid connecting to the database on startup. When starting offline: * Hibernate ORM will not attempt to create a schema automatically, so it must already be created when the application hits the database for the first time. * Quarkus will not check that the database version matches the one configured at build time. Environment variable: Show more |
boolean |
|
||
型 |
デフォルト |
|||
How to store timezones in the database by default for properties of type Environment variable: Show more |
|
|
||
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: Show more |
|
|
||
The preferred JDBC type to use for storing {@link java.time.Duration} values.
<p>
Can be overridden locally using Environment variable: Show more |
string |
|
||
The preferred JDBC type to use for storing {@link java.time.Instant} values.
<p>
Can be overridden locally using Environment variable: Show more |
string |
|
||
The preferred JDBC type to use for storing boolean values.
<p>
Can be overridden locally using Environment variable: Show more |
string |
|
||
The preferred JDBC type to use for storing {@link java.util.UUID} values.
<p>
Can be overridden locally using Environment variable: Show more |
string |
|
||
型 |
デフォルト |
|||
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 For third-party dialects, the expected value is the fully-qualified class name,
for example Environment variable: Show more |
string |
|
||
Specifies the bytes per character to use based on the database’s configured charset. Environment variable: Show more |
int |
|
||
Specifies whether the Environment variable: Show more |
boolean |
|
||
The storage engine to use. Environment variable: Show more |
string |
|||
Specifies the bytes per character to use based on the database’s configured charset. Environment variable: Show more |
int |
|
||
Specifies whether the Environment variable: Show more |
boolean |
|
||
The storage engine to use. Environment variable: Show more |
string |
|||
Support for Oracle’s MAX_STRING_SIZE = EXTENDED. Environment variable: Show more |
boolean |
|
||
Specifies whether this database is running on an Autonomous Database Cloud Service. Environment variable: Show more |
boolean |
|
||
Specifies whether this database is accessed using a database service protected by Application Continuity. Environment variable: Show more |
boolean |
|
||
The Environment variable: Show more |
string |
|||
型 |
デフォルト |
|||
The maximum size of the query plan cache. see # Environment variable: Show more |
int |
|
||
Default precedence of null values in Valid values are: Environment variable: Show more |
|
|
||
Enables IN clause parameter padding which improves statement caching. Environment variable: Show more |
boolean |
|
||
When limits cannot be applied on the database side, trigger an exception instead of attempting badly-performing in-memory result set limits. When pagination is used in combination with a fetch join applied to a collection or many-valued association, the limit must be applied in-memory instead of on the database. This should be avoided as it typically has terrible performance characteristics. Environment variable: Show more |
boolean |
|
||
型 |
デフォルト |
|||
Whether to bootstrap a blocking (JDBC) Hibernate ORM instance for this persistence unit.
<p>
Use {@code quarkus.hibernate-orm.jdbc.enabled} for the default persistence unit
and {@code quarkus.hibernate-orm."<persistence-unit-name>".jdbc.enabled} for named persistence units.
This is the per-persistence-unit replacement for the deprecated {@code quarkus.hibernate-orm.blocking}.
<p>
If not set, this is inferred from whether a JDBC datasource is available for this persistence unit,
as well as the global (deprecated) Environment variable: Show more |
boolean |
|||
The time zone pushed to the JDBC driver. See Environment variable: Show more |
string |
|||
How many rows are fetched at a time by the JDBC driver. Environment variable: Show more |
int |
|||
The number of updates (inserts, updates and deletes) that are sent by the JDBC driver at one time for execution. Environment variable: Show more |
int |
|||
型 |
デフォルト |
|||
Whether to bootstrap a reactive Hibernate Reactive instance for this persistence unit. <p> Use {@code quarkus.hibernate-orm.reactive.enabled} for the default persistence unit and {@code quarkus.hibernate-orm."<persistence-unit-name>".reactive.enabled} for named persistence units. <p> If not set, this is inferred from whether a reactive datasource is available for this persistence unit. Environment variable: Show more |
boolean |
|||
型 |
デフォルト |
|||
The size of the batches used when loading entities and collections.
Environment variable: Show more |
int |
|
||
The maximum depth of outer join fetch tree for single-ended associations (one-to-one, many-to-one). A Environment variable: Show more |
int |
|||
型 |
デフォルト |
|||
The maximum time before an object of the cache is considered expired. Environment variable: Show more |
|
|||
The maximum number of objects kept in memory in the cache. Mutually exclusive with Environment variable: Show more |
長 |
|
||
The maximum total weight of objects kept in memory in the cache. When set, eviction is based on the total weight of cached entries rather than their count. This is useful for entities with highly variable sizes (e.g., JSON blobs). Mutually exclusive with Environment variable: Show more |
長 |
|||
The fully qualified class name of a Only used when Environment variable: Show more |
string |
|||
型 |
デフォルト |
|||
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: Show more |
boolean |
|
||
型 |
デフォルト |
|||
Logs SQL bind parameters. Setting it to true is obviously not recommended in production. Environment variable: Show more |
boolean |
|
||
Show SQL logs and format them nicely. Setting it to true is obviously not recommended in production. Environment variable: Show more |
boolean |
|
||
Format the SQL logs if SQL log is enabled Environment variable: Show more |
boolean |
|
||
Highlight the SQL logs if SQL log is enabled Environment variable: Show more |
boolean |
|
||
Whether JDBC warnings should be collected and logged. Environment variable: Show more |
boolean |
|
||
If set, Hibernate will log queries that took more than specified number of milliseconds to execute. Environment variable: Show more |
長 |
|||
型 |
デフォルト |
|||
Select whether the database schema is generated or not.
This defaults to 'none'. However if Dev Services is in use and no other extensions that manage the schema are present the value will be automatically overridden to 'drop-and-create'. Accepted values: Environment variable: Show more |
|
|
||
If Hibernate ORM should create the schemas automatically (for databases supporting them). Environment variable: Show more |
boolean |
|
||
Whether we should stop on the first error when applying the schema. Environment variable: Show more |
boolean |
|
||
Additional database object types to include in schema management operations. By default, Hibernate ORM only considers tables and sequences when performing schema management operations. This setting allows you to specify additional database object types that should be included, such as "MATERIALIZED VIEW", "VIEW", or other database-specific object types. The exact supported values depend on the underlying database and dialect. Environment variable: Show more |
string |
|||
型 |
デフォルト |
|||
Select whether the database schema DDL files are generated or not. Accepted values: Environment variable: Show more |
|
|
||
Filename or URL where the database create DDL file should be generated. Environment variable: Show more |
string |
|||
Filename or URL where the database drop DDL file should be generated. Environment variable: Show more |
string |
|||
型 |
デフォルト |
|||
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 See the javadoc of Environment variable: Show more |
|
|
|
期間フォーマットについて
期間の値を書くには、標準の 数字で始まる簡略化した書式を使うこともできます:
その他の場合は、簡略化されたフォーマットが解析のために
|