Hibernateは、Java環境のためのオブジェクト・リレーショナル・マッピング・ツールです。Oracle CoherenceとHibernateの機能を組み合せて、たとえば、HibernateをCoherenceのキャッシュ・ストアとして使用したり、CoherenceをHibernateのL2キャッシュとして使用したりすることができます。
この章では次の項について説明します。
Coherenceには、デフォルトのエンティティベースのキャッシュ・ストア実装として、com.tangosol.coherence.hibernate
パッケージ内にあるHibernateCacheStore
(および対応するキャッシュ・ローダー実装であるHibernateCacheLoader
)が組み込まれています。
表3-1は、HibernateCacheStore
クラスとHibernateCacheLoader
クラスの様々なコンストラクタを示しています。詳細な技術情報は、これらのクラスのJavadocを参照してください。
表3-1 Hibernateのキャッシュ・ストア・クラスおよびキャッシュ・ローダー・クラス
クラス名 | 説明 |
---|---|
|
これらのコンストラクタは、キャッシュ・ローダーまたはキャッシュ・ストアの新しいインスタンスを作成するデフォルト・コンストラクタです。これらは、Hibernate |
|
これらのコンストラクタは、クラスパスのデフォルトのHibernate構成( |
|
これらのコンストラクタは、指定された構成ファイル( |
|
これらのコンストラクタは、指定された構成ファイル( |
|
これらのコンストラクタは、 |
Hibernateは、Coherenceのキャッシュ・ストア実装としても使用できます。このアプローチを使用するアプリケーションには、一般的に次の特徴があります。
データ・アクセスおよび管理のためにCoherence APIを使用する。
そのままで使用できるHibernate CacheStore実装に適した単純なオブジェクト・モデルを使用している(より複雑なオブジェクト・モデルを使用しているアプリケーションには、カスタムCacheStore実装を利用できます)。
トランザクション要件が単純である。
Coherence API(ライトビハインドや集計など)を使用して、優れたパフォーマンスを得る必要がある。
HibernateCacheStore
モジュールを使用してアクセスされるHibernateエンティティでは、割り当てられたIDジェネレータを使用する必要があり、定義済のIDプロパティも必要です。
HibernateCacheStore
モジュールで使用されるhibernate.cfg.xml
ファイルのhibernate.hbm2ddl.auto
プロパティは、過剰なスキーマ更新(および検索)を回避するために無効にしてください。
次の例は、エンティティ名のみを受け入れる単純なHibernateCacheStore
コンストラクタの構成方法を示しています。これは、デフォルトの構成パスを使用してHibernateを構成し、クラスパス内でhibernate.cfg.xml
ファイルを探します。また、hibernate.cfg.xml
ファイルのリソース名またはファイル仕様を第2の<init-param>
として指定することもできます(リソース名の場合は<param-type>
要素をjava.lang.String
に設定し、ファイル仕様の場合はjava.io.File
に設定します)。詳細は、HibernateCacheStore
のJavadocを参照してください。
例3-1は、TableA
という名前のNamedCache
キャッシュ・オブジェクトの定義に使用される簡単なcoherence-cache-config.xml
ファイルの例を示しています。これによって、Hibernateエンティティ(com.company.TableA
)のインスタンスがキャッシュされます。追加のエンティティ・キャッシュを定義するには、<cache-mapping>
要素をさらに追加します。
例3-1 Hibernate用のCoherenceキャッシュ構成ファイル
<?xml version="1.0"?> <cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd"> <caching-scheme-mapping> <cache-mapping> <cache-name>TableA</cache-name> <scheme-name>distributed-hibernate</scheme-name> <init-params> <init-param> <param-name>entityname</param-name> <param-value>com.company.TableA</param-value> </init-param> </init-params> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>distributed-hibernate</scheme-name> <backing-map-scheme> <read-write-backing-map-scheme> <internal-cache-scheme> <local-scheme></local-scheme> </internal-cache-scheme> <cachestore-scheme> <class-scheme> <class-name> com.tangosol.coherence.hibernate.HibernateCacheStore </class-name> <init-params> <init-param> <param-type>java.lang.String</param-type> <param-value>{entityname}</param-value> </init-param> </init-params> </class-scheme> </cachestore-scheme> </read-write-backing-map-scheme> </backing-map-scheme> </distributed-scheme> </caching-schemes> </cache-config>
例3-2では、事前定義マクロ{cache-name}
を使用して、キャッシュ・マッピングの<init-params>
部分を不要にできることも示しています。
例3-2 {cache-name}マクロを使用したCoherenceキャッシュ構成ファイル
<?xml version="1.0"?> <cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd"> <caching-scheme-mapping> <cache-mapping> <cache-name>TableA</cache-name> <scheme-name>distributed-hibernate</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>distributed-hibernate</scheme-name> <backing-map-scheme> <read-write-backing-map-scheme> <internal-cache-scheme> <local-scheme></local-scheme> </internal-cache-scheme> <cachestore-scheme> <class-scheme> <class-name> com.tangosol.coherence.hibernate.HibernateCacheStore </class-name> <init-params> <init-param> <param-type>java.lang.String</param-type> <param-value>com.company.{cache-name}</param-value> </init-param> </init-params> </class-scheme> </cachestore-scheme> </read-write-backing-map-scheme> </backing-map-scheme> </distributed-scheme> </caching-schemes> </cache-config>
例3-3では、ネーミング規則で許可される場合は、マッピングを完全に汎用化して、任意の修飾されたクラス名(エンティティ名)のキャッシュ・マッピングを使用できることを示しています。
例3-3 汎用マッピングを指定したcoherence-cache-config.xmlファイルのサンプル
<?xml version="1.0"?> <cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd"> <caching-scheme-mapping> <cache-mapping> <cache-name>com.company.*</cache-name> <scheme-name>distributed-hibernate</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>distributed-hibernate</scheme-name> <backing-map-scheme> <read-write-backing-map-scheme> <internal-cache-scheme> <local-scheme></local-scheme> </internal-cache-scheme> <cachestore-scheme> <class-scheme> <class-name> com.tangosol.coherence.hibernate.HibernateCacheStore </class-name> <init-params> <init-param> <param-type>java.lang.String</param-type> <param-value>{cache-name}</param-value> </init-param> </init-params> </class-scheme> </cachestore-scheme> </read-write-backing-map-scheme> </backing-map-scheme> </distributed-scheme> </caching-schemes> </cache-config>
提供されるHibernateCacheStore
モジュールには、ほとんどのエンティティベース・キャッシュに対するソリューションが用意されていますが、アプリケーション固有のCacheStore
モジュールが必要な場合もありますたとえば、パラメータ化された問合せの使用や、問合せ結果の組込みまたは後処理などの場合です。
キャッシュ・ストアでバッキングされたキャッシュ実装では、アプリケーション・スレッドがキャッシュ・データにアクセスすると、キャッシュ操作が管理 CacheService
APIを使用して、関連するCacheStore
実装に対するコールをトリガーする場合があります。CacheStore
は、CacheService
APIに対するコール・バックを実行できません。これは間接的には、Hibernateがキャッシュ・データへのアクセスを試行できないことを意味します。そのため、CacheLoader
実装またはCacheStore
実装のすべてのメソッドで、Session.setCacheMode(CacheMode.IGNORE)
メソッドをコールするようにして、キャッシュ・アクセスを無効にしておく必要がありますまたは、Hibernate構成で、キャッシュが無効化されたCacheStore
実装のバージョンを使用してクローニングする必要があります(プログラムで実行するか、hibernate.cfg.xml
ファイルを使用します)。
場合によっては、アプリケーション固有の機能でHibernateキャッシュ・ストアを拡張できます。最も明白な事例として、既存のプログラムで構成されたSessionFactory
インスタンスを利用する場合があります。
データベースへのすべてのアクセスがCoherenceを介して実行される場合、読取り操作と書込み操作が(パーティション・キャッシュ・サービスを使用して)キーごとにシリアルで実行されるため、キャッシュ・ストア・モジュールによって必然的にANSIスタイルの反復可能読取りの分離が強制されます。キャッシュ・ストアの操作は複数のパーティション・キャッシュ・ノード(つまり、複数のデータベース・トランザクション)にまたがる場合があるため、反復可能読取りレベルを超えるデータベース分離を設定しても、さらに分離されるわけではありません。反復可能読取りレベルよりも低いデータベース分離レベルを使用すると、予期しない異常が発生せず、データベース・サーバー上の処理負荷が減少する場合があります。
single-cache-entry更新の場合、サーバー障害時(部分更新時の障害を含む)のキャッシュとデータベースの整合性が保証されるため、キャッシュ・ストア操作は完全にフォルト・トレラントになります。フォルト・トレランスには様々なメカニズムがありますが、これはライトスルーとライトビハインドの両方のキャッシュで当てはまります。
Coherenceは、複数のキャッシュ・ストア・インスタンスにまたがる、2フェーズのキャッシュ・ストア操作をサポートしていません。つまり、2つのキャッシュ・エントリが更新されて、別のサーバー上にあるキャッシュ・ストア・モジュールへのコールがトリガーされる場合、一方のデータベースでは更新が成功しますが、もう一方では失敗する可能性があります。この場合、アプリケーション・サーバーのトランザクション・マネージャで、キャッシュアサイド・アーキテクチャ(キャッシュとデータベースを、単一トランザクション内の2つの別個のコンポーネントとして更新する)を使用できます。ほとんどの場合、論理コミットの失敗を回避するように(当然、サーバー障害も発生しないように)データベース・スキーマを設計することが可能です。ライトビハインド・キャッシングでは、put操作がデータベース動作の影響を受けないため(そして、根本的な問題は設計プロセスの初期段階で解決されているため)、この問題は回避されます。
完全にキャッシュされたデータセットの使用が有用なシナリオは、2つあります。1つは、キャッシュで分散問合せを実行する場合で、もう1つは、データベースの障害時でもアプリケーションの処理を続行させる場合です。
分散問合せでは、データベース・サーバーでの問合せの実行と比べて、待機時間の短縮、スループットの向上、データベース・サーバー負荷の低減が実現される可能性があります。セット指向の問合せの場合、正しい問合せ結果を生成するには、データセット全体をキャッシュする必要があります。具体的に言うと、キャッシュに対して発行された問合せで正しい結果を得るには、その問合せはキャッシュされていないデータに依存できません。
分散問合せによりハイブリッド・キャッシュを作成できます。たとえば、問合せ用の完全にキャッシュされたサイズ制限のあるデータセット(先週のデータなど)や、シングルトンの読取りに使用される部分的にキャッシュされた履歴データセットなど、2つの用途のNamedCache
を組み合せることができます。これは、データの複製を回避し、メモリー使用量を抑えるためのアプローチです。
完全にキャッシュされたデータセットは通常、アプリケーションの起動時に(または定期的に)バルクロードされますが、キャッシュ・ストア統合を使用して、キャッシュとデータベースを両方を完全に同期することもできます。
CoherenceをHibernate L2キャッシュ・プロバイダとして使用すると、同じHibernateアプリケーションを実行する複数のJVMでL2キャッシュを共有できます。この場合のCoherenceキャッシングの使用は、Hibernateによって制御されます。このプロバイダを適切に使用するには、Hibernate L2キャッシングについてよく理解しておく必要があります。L2キャッシュとしてのHibernateの詳細は、次のHibernateリファレンス・マニュアルの「パフォーマンスの向上」を参照してください。
http://www.hibernate.org/docs.html
これは、次の特徴を持つアプリケーションに適合する可能性があります。
データ・アクセスおよび管理のためにHibernate APIを使用する。
大きなまたは複雑なオブジェクト・モデルを使用している。
トランザクション要件が複雑である。
同じデータベースにアクセスするHibernateを実行しているアプリケーション・サーバーで構成される大規模なクラスタがある。
Hibernateは、次の3つの主要なキャッシング形式をサポートしています。
セッション・キャッシュ
L2キャッシュ
問合せキャッシュ
session
キャッシュは、Hibernate Session
内のレコードのキャッシングを行います。Hibernate Sessionは、永続データのトランザクションレベルのキャッシュであり、複数のデータベース・トランザクションにまたがる可能性があり、通常はスレッドごとに範囲設定されます。セッション・キャッシュは、非クラスタ・キャッシュ(定義による)として、Hibernateによって全面的に管理されます。
L2および問合せキャッシュは、複数のトランザクションにまたがり、キャッシュ・プロバイダとしてCoherenceの使用がサポートされます。L2キャッシュは、複数のセッションにわたるレコードのキャッシュを(主キーの検索用に)行います。問合せキャッシュは、Hibernate問合せによって生成された結果セットをキャッシュします。Hibernateでは、L2および問合せキャッシュにおいてデータを内部形式で管理するため、これらのキャッシュはHibernateでのみ使用可能です。詳細は、『Hibernate Reference Documentation』(Hibernateに付属)の、2次レベル・キャッシュに関する項を参照してください。
HibernateでCoherenceキャッシュ・プロバイダを使用するには、hibernate.cache.provider_class
プロパティでCoherenceプロバイダ・クラスを指定します。通常、これはデフォルトのHibernate構成ファイルhibernate.cfg.xml
で構成します。例3-4は、CoherenceCacheProvider
(com.tangosol.coherence.hibernate.CacheProvider
)をhibernate.cache.provider_class
プロパティの値としてコールするproperty
要素を示しています。
例3-4 Coherenceプロバイダ・クラスの指定
<property name="hibernate.cache.provider_class">com.tangosol.coherence.hibernate.CoherenceCacheProvider</property>
coherence-hibernate.jar
ファイル(lib/
サブディレクトリにある)をアプリケーション・クラス・パスに追加する必要があります。
Hibernateは、構成プロパティhibernate.cache.use_minimal_puts
で、キャッシュの読取りを増加およびキャッシュの更新を最小化することによって、クラスタ・キャッシュのキャッシュ・アクセスが最適化されます。これは、Coherenceキャッシュ・プロバイダによってデフォルトで有効になっています。このプロパティをfalseに設定すると、キャッシュ管理のオーバーヘッドの増加およびトランザクション・ロールバック数の増加を招く場合があります。
Coherenceキャッシュ・プロバイダでは、タイムアウトになるまでのロック獲得の試行時間を設定できます。この値を指定するには、Javaプロパティtangosol.coherence.hibernate.lockattemptmillis
を使用します。デフォルトは1分です。
デフォルトでは、Coherenceキャッシュ・プロバイダは、coherence-hibernate.jar
ファイルにあるconfig/hibernate-cache-config.xml
という名前のカスタム・キャッシュ構成を使用します。この構成ファイルで、Hibernate L2キャッシュのキャッシュ・マッピングを定義します。必要に応じて、tangosol.coherence.hibernate.cacheconfig
Javaプロパティを使用して、Hibernate L2キャッシュに対して代替のキャッシュ構成リソースを指定できます。マッピングが適切に構成されている場合、このプロパティをアプリケーションのメインcoherence-cache-config.xml
ファイルをポイントするように構成できます。Hibernate固有のキャッシュの管理に専用のキャッシュ・サービスを使用して、キャッシュ・ストア・モジュールでCoherence管理のHibernate L2キャッシュに対するリエントラント・コール・バックが行われないようにすると有益な場合があります。
Coherenceキャッシュ構成ファイルのスキーム・マッピング・セクションでは、hibernate.cache.region_prefix
プロパティでキャッシュ・トポロジを指定できます。たとえば、キャッシュ構成ファイルにnear-*
のワイルドカード・マッピングがあり、Hibernateリージョンの接頭辞プロパティがnear-
に設定されている場合、すべてのHibernateキャッシュがnear-
接頭辞を使用して名前付けされ、near-
*
キャッシュ名パターンで指定したキャッシュ・スキーム・マッピングが使用されます。
接頭辞と修飾エンティティ名の組合せ(たとえば、near-com.company.EntityName
)からキャッシュ・マッピングを作成することによって、または、空白の接頭辞を設定し、修飾エンティティ名のそれぞれにキャッシュ・マッピングを指定することによって、エンティティ別にキャッシュ・トポロジを指定できます。
L2キャッシュは、メモリー使用量が過剰にならないようにサイズを制限する必要があります。Hibernate APIには、完全なエビクション以外に問合せキャッシュを制御する手段がないため、問合せキャッシュでは特にサイズ制限が必要です。
Hibernateでは、通常、キャッシュとデータベースの両方でオプティミスティックな並行性の使用が重視されます。特に、オプティミスティックな並行性では、トランザクションの開始時にアプリケーションで正確なデータを利用できるかどうかが、トランザクション処理では特に重要になります。データが不正確な場合、コミット処理の際にトランザクションが不正確なデータに基づいていることが検出され、トランザクションはコミットされません。オプティミスティックなトランザクションのほとんどは、基礎となるデータへの他のプロセスによる変更に対して調整する必要がありが、キャッシングを使用すると、キャッシュ自体が古くなる可能性が高くなります。Hibernateには、L2キャッシュに対する更新を制御する複数のキャッシュ並行性方針が用意されています。Coherenceでは、クラスタ全体でのキャッシュの一貫性がサポートされるため、さほどの問題は生じませんが、キャッシュの並行性方針を適切に選択することで、アプリケーションの効率の向上につながります。
キャッシュ構成方針は、表レベルで指定できます。一般に、この方針はクラスのマッピング・ファイルで指定する必要があります。
読取りと書込みが行われるアクティビティでは、read-write方針をお薦めします。トランザクション方針は、nonstrict-read-write方針と同様に実装され、Hibernateのオプティミスティックな並行性機能に依存しています。アプリケーションによるデータの更新頻度が少なく、厳密なトランザクション分離を必要としない場合は、nonstrict-read-write方針が適しています。オプティミスティックな並行性に対する影響が許容できる場合は、nonstrict-read-writeのほうがパフォーマンスが高くなることがあります。
読取り専用キャッシングでは、基礎となるデータベースのデータに変更が発生しても、若干古いデータを許容できる場合に、nonstrict-read-write方針を使用します。基礎となるデータベースのデータに変更が発生しない場合は、read-only方針を使用します。
問合せ結果をキャッシュするには、hibernate.cache.use_query_cache
プロパティをtrue
に設定します。これで、結果をキャッシュする必要のある問合せを発行するたびに、Query.setCacheable(true)
メソッドが使用されます。Hibernateのorg.hibernate.cache.QueryKey
インスタンスは、バイナリで比較できないため(順序付けされていないデータ・メンバーの非deterministicシリアライズが実行されているため)、問合せ結果の格納にはサイズ制限のあるローカル・キャッシュまたはレプリケーション・キャッシュを使用します(これにより、キーの比較にhashcode()
またはequals()
メソッドが強制的に使用されます)。
デフォルトの問合せキャッシュ名は、org.hibernate.cache.StandardQueryCache
です(デフォルトのリージョン接頭辞が指定されていない場合。この場合、キャッシュ名の前に[
prefix]
.が付加されます)。キャッシュ構成ファイルを使用して、このキャッシュ名をローカルまたはレプリケーション・トポロジにマップするか、問合せ時に適切にマップされたリージョン名を明示的に指定します。
Hibernate L2キャッシュ・プロトコルでは、クライアントまたはサーバーの障害発生時の完全なフォルト・トレランスがサポートされます。read-writeのキャッシュ並行性方針では、Hibernateによって更新トランザクションの開始時にキャッシュからアイテムがロックアウトされるため、クライアント側の障害では、キャッシュされないエンティティとコミットされていないトランザクションが発生するだけです。サーバー側の障害は、Coherenceによって透過的に処理されます(指定したデータ・バックアップ・カウントによって異なります)。