エンティティマネージャを使用してEntityをデータベースから取得する場合、または作成したEntityを永続性コンテキストにマージする場合、Entityインスタンスが永続性コンテキストキャッシュに格納されます。このキャッシュのライフサイクルは永続性コンテキストと同じです。
以下に永続性コンテキストキャッシュの特徴を説明します。
findメソッド
エンティティマネージャのfindメソッドでEntityを検索すると、まずは永続性コンテキストキャッシュから探します。
キャッシュにある場合は、データベースに問い合わせずにキャッシュされたインスタンスを返却します。キャッシュにない場合は、「7.8.2 永続性ユニットの共有キャッシュ」を探します。共有キャッシュにもない場合、SQL文を発行しデータベースに問い合わせします。検索が成功した場合、Entityインスタンスを永続性コンテキストキャッシュに格納し、アプリケーションに返却します。
クエリメソッド
エンティティマネージャを使用してJPQLクエリメソッドを実行すると、SQL文を発行しデータベースから検索します。ただ、レコードを見つけた場合、レコードと同じプライマリキーのEntityがすでに永続性コンテキストキャッシュに存在しているかどうか確認します。
存在している場合は、現在の永続性コンテキストで行った更新やEntity間のリレーション関係の整合性を保つため、キャッシュしたインスタンスを返却します。
存在していない場合は、永続性ユニットの共有キャッシュを探します。共有キャッシュにもない場合、SQL文を発行しデータベースに問い合わせします。検索が成功した場合、Entityインスタンスを永続性コンテキストキャッシュに格納し、アプリケーションに返却します。
Entityインスタンスの更新、マージ、削除
管理されているEntityインスタンスの更新、削除、または非管理状態のEntityインスタンスの永続性コンテキストへのマージは永続性コンテキストキャッシュに反映されます。
データベースのレコードとの不整合について
エンティティマネージャを使用し各操作を実行する際、同一トランザクションや別トランザクションにおいて、そのエンティティマネージャ以外のアクセス方法でデータベースの同一レコードを更新すると、永続性コンテキスト内で管理されたEntityインスタンスとデータベースのレコード間で不整合が発生する可能性があります。
これを回避するためには、エンティティマネージャの各操作に対するフラッシュやEntityデータの最新化を必要に応じて明示的に実行してください。
エンティティマネージャの各操作をフラッシュする方法は、JPA規約を参照してください。また、Entityデータを最新化する方法については以下に説明します。
Entityデータの最新化
Entityインスタンスの永続化フィールドの最新データをデータベースから取得するため、以下の方法があります。
Entityインスタンスをエンティティマネージャのrefreshメソッドに指定し本メソッドを実行すると、SQL文が発行され、レコードの最新データが取得されます。最新データがEntityインスタンスに反映され永続性コンテキストキャッシュも更新されます。
JPQLクエリーにリフレッシュのヒントを指定しクエリメソッドを実行すると、永続性コンテキストキャッシュと共有キャッシュを検索せずにデータベースに問い合わせます。成功した場合、レコードを取得してEntityインスタンスのコピーを作成して、コピーを共有キャッシュに格納し、もとのEntityインスタンスをアプリケーションに返却します。永続性コンテキストキャッシュにそのEntityがすでに存在した場合、既存のオブジェクトが非管理状態になり、まだフラッシュしなかった修正がデータベースに更新されません。共有キャッシュにEntityがすでに存在した場合、既存のオブジェクトを新しいオブジェクトに上書きします。
注意
データの最新化の各機能における注意事項を以下に説明します。
エンティティマネージャのrefreshメソッドを実行する場合
コンテナ管理のエンティティマネージャを使用した場合、このメソッドをトランザクション中しか実行できないため、データ更新のない操作でもトランザクションを開始する必要があります。
refreshメソッドに指定するEntityインスタンスを取得した時にもSQL文を発行するので、データベースへ2回アクセスします。
Interstage永続性プロバイダのクエリヒントを使用する場合
永続性コンテキストですでに行った更新やEntity間のリレーション関係の整合性を保てません。
Interstage永続性プロバイダの独自機能であるため、その他の永続性プロバイダで該当するヒントがない可能性があり、移植性に影響があります。
リフレッシュ機能は以下のクエリヒントで指定します。
クエリヒント名 | 値 (太字:省略値) | 説明 |
---|---|---|
toplink.refresh | true | キャッシュに問い合わせせずにデータベースを検索します。検索したEntityのコピーを作成しコピーを共有キャッシュに格納します。もとのEntityインスタンスをアプリケーションに返却します。 |
false | データベースからの検索結果をキャッシュ内のEntityと比較し、すでに存在した場合、キャッシュされたEntityインスタンスをアプリケーションに返却します。 | |
toplink.refresh.cascade | CascadeAllParts | 検索したEntityをリフレッシュします。このEntityとリレーションが持つEntityが検索結果に含まれている場合、そのEntityもリフレッシュします。 |
CascadeByMapping | 検索したEntityをリフレッシュします。リレーションのcascade定義にCascadeType.REFRESHまたはCascadeType.ALLを指定したEntityもリフレッシュします。その他のリレーションのEntityインスタンスをリフレッシュしません。 | |
NoCascading | 検索したEntityをリフレッシュしますが、このEntityインスタンスとリレーションが持つEntityインスタンスはキャッシュ内に存在した場合、データをリフレッシュせずにキャッシュしたオブジェクトを返却します。 |
値は大文字と小文字を区別しません。
toplink.refresh.cascadeヒントの設定を有効にするためには、toplink.refreshヒントをtrueに指定する必要があります。
クエリヒントはマッピング定義ファイルdeployment descriptor (orm.xml)のquery-hintタグ、アノテーション(@QueryHint)、またはQuery.setHintメソッドで指定します。
例
リフレッシュのヒントの定義例
@NamedQuery(name="Order.findOrdersByPK", query="SELECT o FROM Order o WHERE o.id = :id", hints={@QueryHint(name="toplink.refresh", value="true"), @QueryHint(name="toplink.refresh.cascade", value="CascadeAllParts")})