第12章 Java 永続 API (JPA)
12.1. Java 永続 API (JPA) について リンクのコピーリンクがクリップボードにコピーされました!
Java Persistence API (JPA) は、Java オブジェクトまたはクラスとリレーショナルデータベース間でデータのアクセス、永続化、および管理を行うための Java 仕様です。この JPA 仕様では、透過オブジェクトまたはリレーショナルマッピングのパラダイムが考慮されます。オブジェクトまたはリレーショナル永続化メカニズムに必要な基本的な API とメタデータが標準化されます。
JPA 自体は製品ではなく仕様にすぎません。それ自体では永続化やその他の処理を実行できません。JPA はインターフェースセットにすぎず、実装を必要とします。
12.2. 単純な JPA アプリケーションの作成 リンクのコピーリンクがクリップボードにコピーされました!
Red Hat JBoss Developer Studio で単純な JPA アプリケーションを作成する場合は、以下の手順を実行します。
JBoss Developer Studio で JPA プロジェクトを作成します。
Red Hat JBoss Developer Studio で、File-→ New -→ Project をクリックします。リストで JPA を見つけ、展開し、JPA Project を選択します。以下のダイアログが表示されます。
図12.1 新規 JPA プロジェクトダイアログ
- プロジェクト名を入力します。
- Target runtime を選択します。ターゲットランタイムがない場合は、『Getting Started with JBoss Developer Studio Tools 』の「Using Runtime Detection to Set Up JBoss EAP from within the IDE」の手順に従って、新しいサーバーとランタイムを定義します。
- JPA version (JPA バージョン) de 2.1 が選択されていることを確認します。
- Configuration (設定) で Basic JPA Configuration (基本的な JPA 設定) を選択します。
- Finish をクリックします。
- 要求されたら、このタイプのプロジェクトを JPA パースペクティブウインドウに関連付けるかどうかを選択します。
新しい永続性設定ファイルを作成および設定します。
- Red Hat JBoss Developer 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_0.xsd" version="2.0"> <persistence-unit name="example" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</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. JPA エンティティー リンクのコピーリンクがクリップボードにコピーされました!
アプリケーションからデータベースへの接続を確立したら、データベースのデータを Java オブジェクトにマッピングできます。データベーステーブルに対してマップするために使用される Java オブジェクトはエンティティーオブジェクトと呼ばれます。
エンティティーは別のエンティティーと関係を持ち、そのような関係はオブジェクトリレーショナルメタデータを介して表現されます。オブジェクトリレーショナルメタデータは、アノテーションを使用してエンティティークラスファイルに直接指定するか、アプリケーションに含まれる persistence.xml という XML 記述ファイルで指定できます。
Java オブジェクトからデータベースへのマッピングの概要は次のとおりです。
- Java クラスはデータベーステーブルにマップします。
- Java インスタンスはデータベース行にマップします。
- Java フィールドはデータベース列にマップします。
12.4. 永続コンテキスト リンクのコピーリンクがクリップボードにコピーされました!
JPA 永続コンテキストには、永続プロバイダーによって管理されるエンティティーが含まれます。永続コンテキストは、データソースと対話するための 1 次レベルトランザクションキャッシュのように動作し、エンティティーインスタンスおよびそれらのライフサイクルを管理します。ロードされたエンティティーは、アプリケーションに返される前に永続コンテキストに置かれます。エンティティーの変更も永続コンテキストに置かれ、トランザクションのコミットが実行されるとデータベースに保存されます。
コンテナー管理永続性 (CMP) コンテキストは、トランザクションにスコープ付けするか (トランザクションスコープの永続コンテキストと呼ばれます)、単一トランザクションを超えて拡張するライフタイムスコープを持つことができます (拡張永続コンテキストと呼ばれます)。enum データタイプを持つ PersistenceContextType プロパティーは、コンテナー管理エンティティーマネージャーの永続コンテキストライフタイムスコープを定義するために使用されます。永続コンテキストのライフタイムスコープは、 EntityManager インスタンスの作成時に定義されます。
12.4.1. トランザクションスコープの永続コンテキスト リンクのコピーリンクがクリップボードにコピーされました!
トランザクションスコープの永続コンテキストは、アクティブな JTA トランザクションと動作します。トランザクションがコミットすると、永続コンテキストはデータソースにフラッシュされます。エンティティーオブジェクトはデタッチされますが、アプリケーションコードによって参照されることがあります。データソースに保存されることが想定されるエンティティーの変更はすべてトランザクション中に行われる必要があります。トランザクション外部で読み取られるエンティティーは、EntityManager 呼び出しが完了するとデタッチされます。
12.4.2. 拡張永続コンテキスト リンクのコピーリンクがクリップボードにコピーされました!
拡張永続コンテキストは複数のトランザクションにまたがり、アクティブが JTA トランザクションがなくてもデータの変更をキューに置けるようにします。コンテナー管理の拡張永続コンテキストは、ステートフルセッション bean のみへインジェクトできます。
12.5. JPA EntityManager リンクのコピーリンクがクリップボードにコピーされました!
JPA エンティティーマネージャーは、永続コンテキストへの接続を表します。エンティティーマネージャーを使用して永続コンテキストによって定義されるデータベースの読み書きが可能です。
永続コンテキストは、javax.persistence パッケージの Java アノテーション @PersistenceContext を介して提供されます。エンティティーマネージャーは、Java クラス javax.persistence.EntityManager を介して提供されます。管理対象 bean では、以下のように EntityManager インスタンスをインジェクトできます。
例: エンティティーマネージャーのインジェクション
@Stateless
public class UserBean {
@PersistenceContext
EntityManager entitymanager;
...
}
12.5.1. アプリケーション管理の EntityManager リンクのコピーリンクがクリップボードにコピーされました!
アプリケーション管理のエンティティーマネージャーは基盤の永続プロバイダーである org.hibernate.ejb.HibernatePersistence への直接アクセスを提供します。アプリケーション管理のエンティティーマネジャーの範囲は、アプリケーションによって作成された時からアプリケーションによってクローズされるまでです。@PersistenceUnit アノテーションを使用して、永続ユニットを javax.persistence.EntityManagerFactory インターフェースにインジェクトできます。これにより、アプリケーション管理のエンティティーマネジャーが返されます。
アプリケーション管理のエンティティーマネージャーは、特定の永続ユニットにて EntityManager インスタンスすべてで JTA トランザクションを使用して伝搬されていない永続コンテキストへアプリケーションがアクセスする必要があるときに使用できます。この場合、各 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.ejb.HibernatePersistence インスタンスが新たに作成されるたびに、新しい永続コンテキストも作成されます。
12.6. EntityManager の利用 リンクのコピーリンクがクリップボードにコピーされました!
/META-INF ディレクトリーに persistence.xml ファイルがある場合、エンティティーマネージャーはロードされ、データベースにアクティブに接続されます。EntityManager プロパティーを使用して、エンティティーマネージャーを JNDI にバインドし、エンティティーを追加、更新、削除、およびクエリーできます。
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 ファイルまたはディレクトリーは、永続ユニットのルートと呼ばれます。
Java 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_0.xsd"
version="2.0">
<persistence-unit name="example" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</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/JPA 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 次レベルキャッシュを設定できます。
-
「単純な JPA アプリケーションの作成」を参照して、Red Hat JBoss Developer 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: 動作は定義されません。プロバイダー固有のデフォルトは提供されます。
-