第12章 Jakarta Persistence
12.1. Jakarta Persistence について
Jakarta Persistence は、Java オブジェクトまたはクラスとリレーショナルデータベース間でデータのアクセス、永続化、および管理を行うための Java 仕様です。この Jakarta Persistence 仕様では、透過オブジェクトまたはリレーショナルマッピングのパラダイムが考慮されます。オブジェクトまたはリレーショナル永続化メカニズムに必要な基本的な API とメタデータが標準化されます。
Jakarta Persistence 自体は製品ではなく仕様にすぎません。それ自体では永続化やその他の処理を実行できません。Jakarta Persistence はインターフェースセットにすぎず、実装を必要とします。
12.2. 単純な JPA アプリケーションの作成
Red Hat CodeReady Studio で単純な JPA アプリケーションを作成する場合は、以下の手順を実行します。
Red Hat CodeReady Studio で JPA プロジェクトを作成します。
Red Hat CodeReady Studio で、File
New Project の順にクリックします。リストで JPA を見つけ、展開し、JPA Project を選択します。以下のダイアログが表示されます。 図12.1 新規 JPA プロジェクトダイアログ
- プロジェクト名を入力します。
- Target runtime を選択します。ターゲットランタイムがない場合は、『Getting Started with Red Hat Developer Studio Tools 』の「Downloading, Installing, and Setting Up JBoss EAP from within the IDE」の手順に従って、新しいサーバーとランタイムを定義します。
- JPA version (JPA バージョン) で 2.1 が選択されていることを確認します。
- Configuration (設定) で Basic JPA Configuration (基本的な JPA 設定) を選択します。
- Finish をクリックします。
- 要求されたら、このタイプのプロジェクトを JPA パースペクティブウインドウに関連付けるかどうかを選択します。
新しい永続性設定ファイルを作成および設定します。
- Red Hat CodeReady Studio で EJB 3.x プロジェクトを開きます。
- Project Explorer (プロジェクトエクスプローラー) パネルでプロジェクトルートディレクトリーを右クリックします。
- New(新規 )→ Other(その他)…
- XML フォルダーから XML File (XML ファイル) を選択し、Next (次へ) をクリックします。
-
親ディレクトリーとして
ejbModule/META-INF/
フォルダーを選択します。 -
ファイルの名前を
persistence.xml
と指定し、Next (次へ) をクリックします。 - Create XML file from an XML schema file (XML スキーマファイルから XML ファイルを作成) を選択し、Next (次へ) をクリックします。
Select XML Catalog entry (XML カタログエントリーを選択) リストから
http://java.sun.com/xml/ns/persistence/persistence_2.0.xsd
を選択し、Next (次へ) をクリックします。図12.2 永続 XML スキーマ
Finish (完了) をクリックしてファイルを作成します。
persistence.xml
がMETA-INF/
フォルダーに作成され、設定可能な状態になります。例: 永続設定ファイル
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_2.xsd" version="2.2"> <persistence-unit name="example" transaction-type="JTA"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <mapping-file>ormap.xml</mapping-file> <jar-file>TestApp.jar</jar-file> <class>org.test.Test</class> <shared-cache-mode>NONE</shared-cache-mode> <validation-mode>CALLBACK</validation-mode> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
12.3. Jakarta Persistence エンティティー
アプリケーションからデータベースへの接続を確立したら、データベースのデータを Java オブジェクトにマッピングできます。データベーステーブルに対してマップするために使用される Java オブジェクトはエンティティーオブジェクトと呼ばれます。
エンティティーは別のエンティティーと関係を持ち、そのような関係はオブジェクトリレーショナルメタデータを介して表現されます。オブジェクトリレーショナルメタデータは、アノテーションを使用してエンティティークラスファイルに直接指定するか、アプリケーションに含まれる persistence.xml
という XML 記述ファイルで指定できます。
Java オブジェクトからデータベースへのマッピングの概要は次のとおりです。
- Java クラスはデータベーステーブルにマップします。
- Java インスタンスはデータベース行にマップします。
- Java フィールドはデータベース列にマップします。
12.4. 永続コンテキスト
Jakarta Persistence 永続コンテキストには、永続プロバイダーによって管理されるエンティティーが含まれます。永続コンテキストは、データソースと対話するための 1 次レベルトランザクションキャッシュのように動作します。これは、エンティティーインスタンスおよびそれらのライフサイクルを管理します。ロードされたエンティティーは、アプリケーションに返される前に永続コンテキストに置かれます。エンティティーの変更も永続コンテキストに置かれ、トランザクションのコミットが実行されるとデータベースに保存されます。
コンテナー管理永続性 (CMP) コンテキストは、トランザクションにスコープ付けするか (トランザクションスコープの永続コンテキストと呼ばれます)、単一トランザクションを超えて拡張するライフタイムスコープを持つことができます (拡張永続コンテキストと呼ばれます)。enum
データタイプを持つ PersistenceContextType
プロパティーは、コンテナー管理エンティティーマネージャーの永続コンテキストライフタイムスコープを定義するために使用されます。永続コンテキストのライフタイムスコープは、EntityManager
インスタンスの作成時に定義されます。
12.4.1. トランザクションスコープの永続コンテキスト
トランザクションスコープの永続コンテキストは、アクティブな Jakarta Transactions トランザクションと動作します。トランザクションがコミットすると、永続コンテキストはデータソースにフラッシュされます。エンティティーオブジェクトはデタッチされますが、アプリケーションコードによって参照されることがあります。データソースに保存されることが想定されるエンティティーの変更はすべてトランザクション中に行われる必要があります。トランザクション外部で読み取られるエンティティーは、EntityManager
呼び出しが完了するとデタッチされます。
12.4.2. 拡張永続コンテキスト
拡張永続コンテキストは複数のトランザクションにまたがり、アクティブが Jakarta Transactions トランザクションがなくてもデータの変更をキューに置けるようにします。コンテナー管理の拡張永続コンテキストは、ステートフルセッション bean のみへインジェクトできます。
12.5. Jakarta Persistence EntityManager
Jakarta Persistence エンティティーマネージャーは、永続コンテキストへの接続を表します。エンティティーマネージャーを使用して永続コンテキストによって定義されるデータベースの読み書きが可能です。
永続コンテキストは、javax.persistence
パッケージの Java アノテーション @PersistenceContext
を介して提供されます。エンティティーマネージャーは、Java クラス javax.persistence.EntityManager
を介して提供されます。管理対象 bean では、以下のように EntityManager
インスタンスをインジェクトできます。
例: エンティティーマネージャーのインジェクション
@Stateless public class UserBean { @PersistenceContext EntityManager entitymanager; ... }
12.5.1. アプリケーション管理の EntityManager
アプリケーション管理のエンティティーマネージャーは基盤の永続プロバイダーである org.hibernate.jpa.HibernatePersistenceProvider
への直接アクセスを提供します。アプリケーション管理のエンティティーマネジャーの範囲は、アプリケーションによって作成された時からアプリケーションによってクローズされるまでです。@PersistenceUnit
アノテーションを使用して、永続ユニットを javax.persistence.EntityManagerFactory
インターフェースにインジェクトできます。これにより、アプリケーション管理のエンティティーマネジャーが返されます。
アプリケーション管理のエンティティーマネージャーは、特定の永続ユニットにて EntityManager
インスタンスすべてで Jakarta Transactions トランザクションを使用して伝搬されていない永続コンテキストへアプリケーションがアクセスする必要があるときに使用できます。この場合、各 EntityManager
インスタンスは新たに分離された永続コンテキストを作成します。EntityManager
インスタンスと関連する PersistenceContext
は、アプリケーションによって明示的に作成および破棄されます。EntityManager
インスタンスはスレッドセーフではないため、EntityManager
インスタンスを直接インジェクトできないときにアプリケーション管理のエンティティーマネージャーを使用することもできます。EntityManagerFactory
はスレッドセーフです。
例: アプリケーション管理のエンティティーマネージャー
@PersistenceUnit EntityManagerFactory emf; EntityManager em; @Resource UserTransaction utx; ... em = emf.createEntityManager(); try { utx.begin(); em.persist(SomeEntity); em.merge(AnotherEntity); em.remove(ThirdEntity); utx.commit(); } catch (Exception e) { utx.rollback(); }
12.5.2. コンテナー管理の EntityManager
コンテナー管理のエンティティーマネージャーは、アプリケーションの基盤となる永続プロバイダーを管理します。トランザクションスコープの永続コンテキストまたは拡張永続コンテキストを使用できます。コンテナー管理のエンティティーマネージャーは、必要に応じて基盤となる永続プロバイダーのインスタンスを作成します。基盤の永続プロバイダー org.hibernate.jpa.HibernatePersistenceProvider
インスタンスが新たに作成されるたびに、新しい永続コンテキストも作成されます。
12.6. EntityManager の利用
/META-INF
ディレクトリーに persistence.xml
ファイルがある場合、エンティティーマネージャーはロードされ、データベースにアクティブに接続されます。EntityManager
プロパティーを使用して、エンティティーマネージャーを JNDI にバインドし、エンティティーを追加、更新、削除、およびクエリーできます。
Hibernate でセキュリティーマネージャーの使用を計画している場合は、EntityManagerFactory
が JBoss EAP サーバーによってブートストラップされている場合のみ Hibernate がサポートすることに注意してください。EntityManagerFactory
または SessionFactory
がアプリケーションによってブートストラップされている場合はサポートされません。セキュリティーマネージャーに関する詳細は、『 How to Configure Server Security』の「 Java Security Manager 」を参照してください。
12.6.1. EntityManager の JNDI へのバインディング
デフォルトでは、JBoss EAP は EntityManagerFactory
を JNDI にバインドしません。jboss.entity.manager.factory.jndi.name
プロパティーを設定すると、アプリケーションの persistence.xml
ファイルでこれを明示的に設定できます。このプロパティーの値は、EntityManagerFactory
をバインドする JNDI の名前にする必要があります。
また、jboss.entity.manager.jndi.name
プロパティーを使用すると、コンテナー管理でトランザクションスコープのエンティティーマネージャーを JNDI にバインドすることもできます。
例: EntityManager
および EntityManagerFactory
の JNDI へのバインド
<property name="jboss.entity.manager.jndi.name" value="java:/MyEntityManager"/> <property name="jboss.entity.manager.factory.jndi.name" value="java:/MyEntityManagerFactory"/>
例: EntityManager
を使用したエンティティーの格納
public User createUser(User user) { entityManager.persist(user); return user; }
例: EntityManager
を使用したエンティティーの更新
public void updateUser(User user) { entityManager.merge(user); }
例: EntityManager
を使用したエンティティーの削除
public void deleteUser(String user) { User user = findUser(username); if (user != null) entityManager.remove(user); }
例: EntityManager
を使用したエンティティーのクエリー
public User findUser(String username) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<User> criteria = builder.createQuery(User.class); Root<User> root = criteria.from(User.class); TypedQuery<User> query = entityManager .createQuery(criteria.select(root).where( builder.equal(root.<String> get("username"), username))); try { return query.getSingleResult(); } catch (NoResultException e) { return null; } }
12.7. 永続ユニットのデプロイ
永続ユニットは、以下が含まれる論理グループです。
- エンティティーマネージャーファクトリーおよびそのエンティティーマネージャーの設定情報。
- エンティティーマネージャーによって管理されるクラス。
- データベースへのクラスのマッピングを指定するメタデータのマッピング。
persistence.xml
ファイルには、データソース名を含む永続ユニット設定が含まれています。/META-INF/
ディレクトリーに persistence.xml
ファイルが含まれる JAR ファイルまたはディレクトリーは、永続ユニットのルートと呼ばれます。
Jakarta EE 環境では、永続ユニットのルートは以下の 1 つである必要があります。
- EJB-JAR ファイル
-
WAR ファイルの
/WEB-INF/classes/
ディレクトリー -
WAR ファイルの
/WEB-INF/lib/
ディレクトリーにある JAR ファイル - EAR ライブラリーディレクトリーの JAR ファイル
- アプリケーションクライアントの JAR ファイル
例: 永続設定ファイル
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_2.xsd" version="2.2"> <persistence-unit name="example" transaction-type="JTA"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <mapping-file>ormap.xml</mapping-file> <jar-file>TestApp.jar</jar-file> <class>org.test.Test</class> <shared-cache-mode>NONE</shared-cache-mode> <validation-mode>CALLBACK</validation-mode> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
12.8. 2 次キャッシュ
12.8.1. 2 次キャッシュ
2 次キャッシュとは、アプリケーションセッション外部で永続化された情報を保持するローカルデータストアのことです。このキャッシュは永続プロバイダーにより管理され、アプリケーションとデータを分離することでランタイムを改善します。
JBoss EAP では、以下の目的のためにキャッシュがサポートされます。
- Web セッションのクラスタリング
- ステートフルセッション Bean のクラスタリング
- SSO クラスタリング
- Hibernate 2 次キャッシュ
- Jakarta Persistence の 2 次キャッシュ
各キャッシュコンテナーは repl
および dist
キャッシュを定義します。これらのキャッシュは、ユーザーアプリケーションで直接使用しないでください。
12.8.1.1. デフォルトの 2 次キャッシュプロバイダー
Infinispan は、JBoss EAP のデフォルトの 2 次キャッシュプロバイダーです。Infinispan は、オプションのスキーマを持つ分散型のインメモリーキーと値のデータストアで、Apache License 2.0 で利用できます。
12.8.1.1.1. 永続ユニットでの 2 次レベルキャッシュの設定
永続ユニットの shared-cache-mode
要素を使用して 2 次レベルキャッシュを設定できます。
-
「単純な Jakarta Persistence アプリケーションの作成」を参照して、Red Hat CodeReady Studio で
persistence.xml
ファイルを作成します。 以下の内容を
persistence.xml
ファイルに追加します。<persistence-unit name="..."> (...) <!-- other configuration --> <shared-cache-mode>SHARED_CACHE_MODE</shared-cache-mode> <properties> <property name="hibernate.cache.use_second_level_cache" value="true" /> <property name="hibernate.cache.use_query_cache" value="true" /> </properties> </persistence-unit>
SHARED_CACHE_MODE
要素には以下の値を指定できます。-
ALL
: すべてのエンティティーがキャッシュ可能と見なされます。 -
NONE
: キャッシュ可能と見なされるエンティティーはありません。 -
ENABLE_SELECTIVE
: キャッシュ可能とマークされたエンティティーのみがキャッシュ可能と見なされます。 -
DISABLE_SELECTIVE
: 明示的にキャッシュ不可能であるとマークされたエンティティーを除くすべてのエンティティーがキャッシュ可能と見なされます。 -
UNSPECIFIED
: 動作は定義されません。プロバイダー固有のデフォルトは提供されます。
-