この項では、次の構成について説明します。
各構成の例で示されているサンプル・コードは、http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip
から取得できます。
TopLink Grid Coherenceのグリッド・キャッシュ構成では、CoherenceをTopLink共有(L2)キャッシュとして使用します。これにより、Coherenceのキャッシュにすべて事前ロードできずデータベースでホストされるデータに依存するJPAアプリケーションに対してCoherenceのデータ・グリッドを適用できます。事前ロードができない理由には、Coherenceのフィルタの機能セットを超える非常に複雑な問合せ、サード・パーティ製データベースの更新による古いキャッシュ、ネイティブSQL問合せ、ストアド・プロシージャやトリガーへの依存などがあります。
Coherenceをグリッド・キャッシュとして使用すると、ローカル・グリッド・キャッシュを調整しなくても、TopLinkを大規模なクラスタにスケール・アップできます。エンティティに対する更新は、トランザクションがコミットされると即時にすべてのCoherenceクラスタ・メンバーで使用可能になります。
一般的な処理は次のとおりです。
主キー問合せでは、最初にCoherenceからのエンティティの取得が試行されます。これに失敗すると、データベースが問合せされ、Coherenceが問合せ結果で更新されます。「オブジェクトの読取り」を参照してください。
非主キー問合せがデータベースに対して実行され、結果がCoherenceに照らしてチェックされます。これによって、キャッシュされたエンティティのオブジェクト構築で発生する処理を回避しています。新しく問合せされたエンティティがCoherenceに挿入されます。
書込み操作によりデータベースが更新されます。コミットが正常に完了すると、更新されたエンティティがCoherenceに挿入されます。「オブジェクトの書込み」を参照してください。
詳細な例については、「例」を参照してください。
Coherenceのグリッド・キャッシュ構成においては、主キー問合せを除くすべての読取り問合せがデータベースに送られます。主キー問合せは、最初にCoherenceキャッシュに対して実行されます。キャッシュ・ミスがあった場合は、データベース問合せが実行されます。
データベースから問合せされたすべてのエンティティはCoherenceキャッシュに挿入されます。これにより、これらのエンティティはすべてのクラスタ・メンバーに対して即時に使用可能になります。TopLinkはデフォルトで、データベース結果からの新しいエンティティの構成を回避するためにキャッシュを使用するので、この動作が非常に有効になります。
TopLinkは、問合せの結果返された行ごとに、結果の行の主キーを使用して、キャッシュから対応するエンティティを問い合せます。キャッシュにエンティティが含まれていれば、そのエンティティが使用され、新しいエンティティは構築されません。このアプローチでは問合せのコストを削減できるため、特にウォーム・キャッシュを使用する場合はアプリケーションのパフォーマンスが大幅に向上する可能性があります。
この図は、Coherenceのグリッド・キャッシュ構成における問合せを示しています。
アプリケーションがfind
問合せを発行します。
主キー問合せでは、TopLinkは最初にCoherenceキャッシュを問い合せます。
オブジェクトがCoherenceキャッシュに存在しない場合、TopLinkはデータベースを問い合せます。
主キー問合せを除くすべての読取り問合せでは、TopLinkは最初にデータベースを問い合せます。
読み取られたオブジェクトは、Coherenceキャッシュに挿入
されます。
Coherenceのグリッド・キャッシュ構成においては、TopLinkがすべてのデータベース書込み(挿入、更新、削除)を実行します。その後、Coherenceキャッシュがデータベースへの変更を反映するように更新されます。TopLinkには、大量のデータを書き込む際のパフォーマンス機能が数多く用意されています(バッチ書込み、パラメータ・バインディング、ストアド・プロシージャ・サポート、およびデータベース制約を満たすための文の順序付けなど)。
この図は、Coherenceのグリッド・キャッシュ構成における問合せを示しています。
アプリケーションがcommit
問合せを発行します。
TopLinkがデータベースを更新します。
トランザクションが正常に完了すると、TopLinkはCoherenceキャッシュを更新します。
これらの例で示されているサンプル・コードは、http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip
から取得できます。
キャッシュ構成(coherence-cache-config.xml
)で、この例に示すように、キャッシュを定義し、リレーションシップのシリアライズをサポートするためにラッパー・シリアライザを構成します。
例4 キャッシュの構成
<cache-config> <caching-scheme-mapping> <cache-mapping> <cache-name>*</cache-name> <scheme-name>eclipselink-distributed</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>eclipselink-distributed</scheme-name> <service-name>EclipseLinkJPA</service-name> <!-- Configure a wrapper serializer to support serialization of relationships. --> <serializer> <class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name> </serializer> <backing-map-scheme> <!-- Backing map scheme with no eviction policy --> <local-scheme> <scheme-name>unlimited-backing-map</scheme-name> </local-scheme> </backing-map-scheme> </backing-map-scheme> <autostart>true</autostart> </distributed-scheme> </caching-schemes></cache-config>
Coherenceのグリッド・キャッシュを使用するようエンティティを構成するには、例5に示すようにCoherencInterceptor
クラスを使用します。このクラスは、内部のTopLink GridキャッシュへのすべてのTopLinkコールをインターセプトし、それらをCoherenceにリダイレクトします。
例5 エンティティの構成
import oracle.eclipselink.coherence.integrated.cache.CoherenceInterceptor; import org.eclipse.persistence.annotations.Customizer; @Entity @CacheInterceptor(value = CoherenceInterceptor.class) public class Employee { ...
例6では、TopLinkはinsertを実行して新しい従業員を作成しています。エンティティはEntityManger
によって永続化され、データベースに挿入されます。
例6 オブジェクトの挿入
EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee"); // Create an Employee with an Address and PhoneNumber EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Employee employee = createEmployee(); em.persist(employee); em.getTransaction().commit(); em.close();
トランザクションが正常に完了すると、Coherenceキャッシュが更新されます。
例7では、TopLinkが従業員を検出すると、読取り問合せがCoherenceキャッシュに送られます。
例7 オブジェクトの問合せ
EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee"); EntityManager em = emf.createEntityManager(); List<Employee> employees = em.createNamedQuery("Employee.findByLastNameLike").setParameter("lastName", "Smit%").getResultList(); for (Employee employee : employees) { System.err.println(employee); for (PhoneNumber phone : employee.getPhoneNumbers()) { System.err.println("\t" + phone); } } emf.close();
TopLink Gridの読取り構成は、(比較的安定した)大容量のデータに高速にアクセスする必要があり、変更をデータベースに同期的に書き込む必要のあるエンティティに対して使用してください。これらのエンティティでは、通常はCoherenceキャッシュへの移入にキャッシュ・ウォーミングが使用されますが、必要に応じて個々の問合せをデータベースに送ることもできます。
一般的な処理は次のとおりです。
読取り操作では、Coherenceキャッシュからオブジェクトが取得されます。CacheLoaderを構成してもJPQL問合せに影響はありません。「オブジェクトの読取り」を参照してください。
書込み操作によりデータベースが更新されます。コミットが正常に完了すると、更新されたエンティティがCoherenceに挿入されます。「オブジェクトの書込み」を参照してください。
詳細な例については、「例」を参照してください。
グリッド読取り構成においては、エンティティに対するすべての読取り問合せはCoherenceキャッシュに送られます。TopLink Gridでは、問合せの処理時間を短縮するために、データ・グリッド全体での問合せのパラレル処理をサポートしています。Coherenceには、オブジェクト形式のデータが含まれており、データベースとの通信やオブジェクト構築で発生するやり取りを削減します。
グリッド読取り構成を使用する場合、find(...)
によってリクエストされたエンティティがCoherence内に存在しなければ、null
が返されます。ただし、そのエンティティのキャッシュに対してCacheLoader
が構成されていれば、Coherenceはそのデータベースからオブジェクトをロードしようとします。これは、主キー問合せにのみ該当します。
CacheLoader
を構成しても、Coherenceフィルタに変換されるJPQL問合せに影響を与えることはありません。Coherenceはフィルタを使用して検索する際に、キャッシュ内のエンティティ・セットに対してのみ操作を実行するため、データベースは問合せされません。ただし、次の例に示すように、oracle.eclipselink.coherence.integrated.querying.IgnoreDefaultRedirector
を使用して、問合せごとに問合せをCoherenceではなくデータベースに送ることも可能です。
query.setHint(QueryHints.QUERY_REDIRECTOR, new IgnoreDefaultRedirector());
データベース問合せで取得されたオブジェクトはすべて、以降の問合せで使用できるようCoherenceキャッシュに追加されます。この構成はデフォルトで、Coherenceを介してエンティティに対するすべての問合せを解決します。そのため、Coherenceのキャッシュをすべての問合せ対象のデータでウォーミングする必要があります。
CacheStore
には、グリッド読取り構成との互換性はありません。これは、EclipseLinkがすべてのデータベース更新を実行し、更新済のオブジェクトをCoherenceに伝播するためです。CacheStore
を使用すると、Coherenceは書き込まれたばかりのオブジェクトを再び書き込もうとすることになります。
EclipseLink JPAの問合せヒントの使用方法の詳細は、EclipseLinkのドキュメントを参照してください。
この図は、グリッド読取り構成における問合せを示しています。
アプリケーションがJPQL問合せを発行します。
TopLinkはCoherenceキャッシュに対してフィルタを実行します。
TopLinkはCoherenceキャッシュからの結果のみを返します。データベースは問合せされません。
Coherenceのグリッド読取り構成においては、TopLinkがすべてのデータベース書込み(挿入、更新、削除)を直接実行します。その後、Coherenceキャッシュがデータベースへの変更を反映するよう更新されます。TopLinkには、大量のデータを書き込む際のパフォーマンス機能が数多く用意されています(バッチ書込み、パラメータ・バインディング、ストアド・プロシージャ・サポート、およびデータベース制約を満たすための文の順序付けなど)。
このアプローチは、2つの長所をいずれも生かすことができます。1つはデータベースの更新が効率的に行われること、そしてもう1つはCoherenceのデータ・グリッド全体に対して問合せをパラレルに実行できることです。さらに、個々の問合せをデータベースに直接送ることもできます。
この図は、グリッド読取り構成における問合せを示しています。
アプリケーションがcommit
問合せを発行します。
TopLinkがデータベースを更新します。
トランザクションが正常に完了すると、TopLinkはCoherenceキャッシュを更新します。
これらの例で示されているサンプル・コードは、http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip
から取得できます。
キャッシュ構成(coherence-cache-config.xml
)で、この例に示すように、キャッシュを定義し、リレーションシップのシリアライズをサポートするためにラッパー・シリアライザを構成します。
例8 キャッシュの構成
<cache-config> <caching-scheme-mapping> <cache-mapping> <cache-name>*</cache-name> <scheme-name>eclipselink-distributed-readonly</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>eclipselink-distributed-readonly</scheme-name> <service-name>EclipseLinkJPAReadOnly</service-name> <!-- Configure a wrapper serializer to support serialization of relationships. --> <serializer> <class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name> </serializer> <backing-map-scheme> <read-write-backing-map-scheme> <internal-cache-scheme> <local-scheme /> </internal-cache-scheme> <!-- Define the cache scheme --> <cachestore-scheme> <class-scheme> <class-name>oracle.eclipselink.coherence.integrated.EclipseLinkJPACacheLoader</class-name> <init-params> <param-type>java.lang.String</param-type> <param-value>{cache-name}</param-value> </init-param> <init-param> <param-type>java.lang.String</param-type> <param-value>employee</param-value> </init-param> </init-params> </class-scheme> </cachestore-scheme> <!-- The read-only = true required when using a CacheLoader. If omitted, Coherence will attempt to call CacheStore methods that are not available on CacheLoader. --> <read-only>true</readonly> </read-write-backing-map-scheme> </backing-map-scheme> <autostart>true</autostart> </distributed-scheme> </caching-schemes></cache-config>
Coherenceをリードスルーするようエンティティを構成するには、次の例に示すようにCoherenceReadCustomizer
を使用します。
例9 エンティティの構成
import oracle.eclipselink.coherence.integrated.config.CoherenceReadCustomizer; import org.eclipse.persistence.annotations.Customizer; @Entity @Customizer(CoherenceReadCustomizer.class) public class Employee { ... }
例10では、TopLinkはinsertを実行して新しい従業員を作成しています。トランザクションが正常に完了すると、新しいオブジェクトがその主キーによってCoherenceに挿入されます。
例10 オブジェクトの挿入
EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");// Create an Employee with an Address and PhoneNumber EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Employee employee = createEmployee(); em.persist(employee); em.getTransaction().commit(); em.close(); emf.close();
従業員を検索する際に、読取り問合せがCoherenceキャッシュに送られます。次の例に示すように、JPQL問合せがCoherenceフィルタに変換されます。
例11 オブジェクトの問合せ
EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee"); EntityManager em = emf.createEntityManager(); List<Employee> employees = em.createNamedQuery("Employee.findByLastNameLike").setParameter("lastName", "Smit%").getResultList(); for (Employee employee : employees) { System.err.println(employee); for (PhoneNumber phone : employee.getPhoneNumbers()) { System.err.println("\t" + phone); } }emf.close();
特定のID(キー)を使用してCoherenceキャッシュからオブジェクトを取得するには、em.find(Entity.class, ID)
を使用します。指定したIDを持つオブジェクトがキャッシュに存在しない場合は、データベースを問い合せるようCoherenceのCacheLoader
を構成して、オブジェクトを検出することもできます。
グリッド・エンティティ構成は、(比較的安定した)大容量のデータに高速にアクセスする必要があり、実行される更新が比較的少ないアプリケーションに対して使用してください。ライトビハインドを使用してこの構成をCoherenceのCacheStore
と組み合せると、データベース更新を非同期に実行することにより、アプリケーションのレスポンス時間を向上させることができます。
一般的な処理は次のとおりです。
読取り操作では、Coherenceキャッシュからオブジェクトが取得されます。「オブジェクトの読取り」を参照してください。
書込み操作により、オブジェクトがCoherenceキャッシュに挿入されます。CacheStoreが構成されている場合、TopLinkはデータベースに対する書込み操作も実行します。「オブジェクトの書込み」を参照してください。
詳細な例については、「例」を参照してください。
グリッド・エンティティ構成におけるオブジェクトの読取りは、グリッド読取り構成と同じです。詳細は、「オブジェクトの読取り」を参照してください。
グリッド・エンティティ構成では、EntityManger
を介して永続化、更新またはマージされたオブジェクトはすべて、適切なCoherenceキャッシュに挿入されます。Coherenceキャッシュ内のオブジェクトをデータベースに対して永続化するには、キャッシュごとにEclipseLink CacheStore
(oracle.eclipselink.coherence.integrated.EclipseLinkJPACacheStore
)を構成する必要があります。
ライトビハインドを使用して更新済のオブジェクトの一括書込みを非同期的に行うよう、CacheStoreを構成することもできます。詳細は、Coherenceの開発者ガイドを参照してください。
この項では、オブジェクトを書き込む際に注意する必要のある項目について説明します。
CacheStore
を使用する場合、Coherenceはすべての書込み操作が成功することを前提とするため、TopLinkに失敗を通知しません。このため、Coherenceキャッシュがデータベースの内容と異なることがあります。Coherenceおよびサード・パーティ製アプリケーションによりデータベースが更新された場合、データが破損しないよう保護するためにオプティミスティック・ロックを使用することはできません。
各クラスが別々のキャッシュ内に入っていることがあるため、Coherenceはストアへの削除コールを必要な順序または正しいタイミングで発行できないことがあります。この場合、制約準拠は保証されず、書込み操作が次のエラーで失敗する可能性があります。
org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.BatchUpdateException: ORA-02292: integrity constraint violated - child record found Error Code: 2292
データベース外部キー制約を確認し、必要に応じて削除してください。
この図は、グリッド・エンティティ構成における問合せを示しています。
アプリケーションがcommit
を発行します。
TopLinkはすべての問合せを送って、Coherenceキャッシュを更新します。
CoherenceのCacheStoreを構成すると(オプション)、TopLinkはデータベースも更新します。
キャッシュ構成(coherence-cache-config.xml
)で、この例に示すように、リレーションシップのシリアライズをサポートするためにラッパー・シリアライザを構成します。
これらの例で示されているサンプル・コードは、http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip
から取得できます。
例12 キャッシュの構成
<cache-config> <caching-scheme-mapping> <cache-mapping> <cache-name>*</cache-name> <scheme-name>eclipselink-distributed-readwrite</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>eclipselink-distributed-readwrite</scheme-name> <service-name>EclipseLinkJPAReadWrite</service-name> <!-- Configure a wrapper serializer to support serialization of relationships. --> <serializer> <class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name> </serializer> <backing-map-scheme> <read-write-backing-map-scheme> <internal-cache-scheme> <local-scheme /> </internal-cache-scheme> <!-- Define the cache scheme --> <cachestore-scheme> <class-scheme> <class-name>oracle.eclipselink.coherence.integrated.EclipseLinkJPACacheStore</class-name> <init-params> <init-param> <param-type>java.lang.String</param-type> <param-value>{cache-name}</param-value> </init-param> <init-param> <param-type>java.lang.String</param-type> <param-value>employee</param-value> </init-param> </init-params> </class-scheme> </cachestore-scheme> </read-write-backing-map-scheme> </backing-map-scheme> <autostart>true</autostart> </distributed-scheme> </caching-schemes> </cache-config>
Coherenceをリードスルーするようエンティティを構成するには、次の例に示すようにCoherenceReadWriteCustomizer
を使用します。
例13 エンティティの構成
import oracle.eclipselink.coherence.integrated.config.CoherenceReadWriteCustomizer; import org.eclipse.persistence.annotations.Customizer; @Entity @Customizer(CoherenceReadWriteCustomizer.class) public class Employee { ... }
例14では、TopLinkはinsertを実行して新しい従業員を作成しています。エンティティはEntityManger
によって永続化され、適切なCoherenceキャッシュに挿入されます。
例14 オブジェクトの永続化
EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee"); // Create an Employee with an Address and PhoneNumber EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Employee employee = createEmployee(); em.persist(employee); em.getTransaction().commit(); em.close();
次の例に示すように、従業員を検索する際に、読取り問合せがCoherenceキャッシュに送られます。
例15 オブジェクトの問合せ
EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee"); EntityManager em = emf.createEntityManager(); List<Employee> employees = em.createNamedQuery("Employee.findByLastNameLike").setParameter("lastName", "Smit%").getResultList(); for (Employee employee : employees) { System.err.println(employee); for (PhoneNumber phone : employee.getPhoneNumbers()) { System.err.println("\t" + phone); } } emf.close();
特定のID(キー)を使用してCoherenceキャッシュからオブジェクトを取得するには、em.find(Entity.class, ID)
を使用します。指定したIDを持つオブジェクトがキャッシュに存在しない場合は、データベースを問い合せるようCoherenceのCacheLoader
を構成して、オブジェクトを検出することもできます。