Hitachi

Cosminexus V11 アプリケーションサーバ 機能解説 互換編


8.4.5 データベースとの同期

トランザクションのコミットまたはflushメソッドの実行時に,エンティティの状態がデータベースに書き込まれます。一方,明示的にrefreshを呼び出さないかぎり,メモリにロードされたエンティティの状態のリフレッシュは実行されません。

ここでは,データベースへのエンティティ情報の書き込みと,データベースからのエンティティ情報の読み込みについて説明します。

〈この項の構成〉

(1) データベースへのエンティティ情報の書き込み

flush操作またはトランザクションのコミットでのエンティティの状態遷移について説明します。次の表ではエンティティAの状態ごとに状態遷移の結果を示しています。

表8‒12 flush操作またはトランザクションのコミットでのエンティティインスタンスの状態遷移

エンティティAの状態

状態遷移の結果

new

flush操作は無視されます。

managed

データベースと同期されます。

removed

エンティティAはデータベースから削除されます。

detached

flush操作は無視されます。

また,managed状態のエンティティAがエンティティBに対してリレーションシップを持っている場合,flush処理の延長で次の表に示す条件に従って,persist操作がカスケードされます。

表8‒13 関連するエンティティBへのflush処理およびコミットでのpersist操作のカスケード

エンティティBへのリレーションシップのcascade属性の指定

エンティティBの状態

結果

PERSISTまたはALLが指定されている

persist操作がエンティティBにカスケードされます。

PERSISTまたはALLが指定されていない

new

  • flush操作の場合

    IllegalStateExceptionが発生してトランザクションはロールバックにマークされます。

  • コミット処理の場合

    IllegalStateExceptionが発生してトランザクションのコミットに失敗します。

managed

データベースと同期化されます。

removed

  • flush操作の場合

    IllegalStateExceptionが発生してトランザクションはロールバックにマークされます。

  • コミット処理の場合

    IllegalStateExceptionが発生してトランザクションのコミットに失敗します。

detached

  • エンティティAがリレーションシップの所有者の場合

    リレーションシップの変更はデータベースと同期されます。

  • エンティティBがリレーションシップの所有者の場合

    例外が発生します。CJPAプロバイダでは,この場合の動作はサポート対象外となります。

(凡例)−:該当しない

なお,トランザクションの外でflushメソッドを呼び出すと,TransactionRequiredExceptionが発生します。

ポイント

リレーションシップとデータベースに対する永続化の関連

  • 双方向のリレーションシップを持つmanaged状態のエンティティは,リレーションシップの所有者側で保持される参照を基に永続化されます。アプリケーション開発者は,変更が発生したときに所有者側と被所有者側でそれぞれ,メモリ上の状態に矛盾がないようにエンティティを保持するようアプリケーションを作成してください。

  • 単方向のOneToOne,OneToManyの場合,エンティティで定義しているリレーションシップの関係とデータベースのテーブル間の関係が合っていることは,開発者の責任で保証してください。

(2) データベースからのエンティティ情報の読み込み

EntityManagerのrefreshメソッドを呼び出すと,それまでに行われたエンティティの変更は破棄され,データベースの内容でエンティティの状態を上書きします。このとき,データベース上に対応する行が存在しない場合はEntityNotFoundExceptionが発生します。

エンティティがmanaged状態以外の場合に,EntityManagerのrefreshメソッドを呼び出すとIllegalArgumentExceptionが発生します。

(a) データベースからのエンティティ情報を読み込むタイミング

refreshメソッドもしくはfindメソッドの実行時,またはクエリの発行時に,データベースからエンティティが読み込まれます。このときに,関連するエンティティもあわせて読み込むことができます。これをフェッチ戦略といいます。フェッチ戦略は各リレーションシップのfetch属性で指定します。fetch属性には次の2種類のどちらかを指定します。

  • FetchType.EAGER

    データベースからエンティティの情報を読み込むときに,関連するフィールドやエンティティの情報を読み込みます。

  • FetchType.LAZY

    フィールドまたは関連先に初めてアクセスしたときにデータベースからの読み込みが実行されます。これを,Lazyローディングといいます。

FetchType.EAGERを指定するとデータベースからエンティティの情報を読み込むたびに,関連するフィールドやエンティティの情報を読み込みます。このため,不要な関連先のエンティティの取得を回避したい場合は,FetchType.LAZYを指定してください。

CJPAプロバイダでのfetch属性のサポート範囲を次の表に示します。

表8‒14 リレーションシップごとのfetch属性のサポート範囲

リレーションシップのアノテーション

サポート範囲

@ManyToMany

デフォルトはFetchType.LAZYです。

@OneToMany

デフォルトはFetchType.LAZYです。

@OneToOne

デフォルトはFetchType.EAGERです。なお,LAZYを指定したときには,(b)を参照してください。

@ManyToOne

デフォルトではFetchType.EAGERです。なお,LAZYを指定したときには,(b)を参照してください。

@Basic

fetch属性は無視されます。デフォルトのFetchType.EAGERが常に適用されます。

(b) @OneToOneおよび@ManyToOneでのLAZYフェッチ

@OneToOneおよび@ManyToOneのリレーションシップに対してフェッチ戦略にLAZYを指定した場合,エンティティクラスのローディング時に,LAZYを指定したフィールドのgetterメソッドにバイナリコードを埋め込みます。

getterメソッドが呼び出されると,埋め込んだバイナリコードの処理を通して,データベースから関連先のエンティティを取得します。getterメソッドがバイナリの埋め込み対象になるため,リレーションの対象となるフィールドにアクセスするためのgetterメソッドを設定しておく必要があります。また,そのgetterメソッドに@OneToOneまたは@ManyToOneを設定しておく必要があります。

注意事項

getterメソッドでは,リレーションシップのtargetEntityの型から,関連先のエンティティの型を決定します。targetEntityに指定するクラスの型は,フィールド・プロパティの型にキャストできる必要があります。