この章では、ディスクリプタについて紹介および説明します。EclipseLinkでは、ディスクリプタを使用して、あるデータ・ソースによって特定クラスのインスタンスがどのように表現されるかを定義した情報を格納します。ディスクリプタには、クラスのインスタンス変数を、データ・ソースおよび、値の格納と取得に使用されるトランスフォーメーション・ルーチンに関連付けるマッピングを含めます。それによって、ディスクリプタは、Javaオブジェクトとそのデータ・ソース表現を接続する役目を果します。
この章の内容は次のとおりです。
次の項では、オブジェクト・リレーショナルとMOXyのディスクリプタに共通の概念について説明します。
ディスクリプタには、あるデータ・ソースによって特定オブジェクト・クラスのインスタンスがどのように表現されるかを定義したすべての情報を格納します。ディスクリプタAPIを使用すると、Javaコードを介してEclipseLinkディスクリプタを定義または修正できます。ディスクリプタAPIのクラスは、主としてorg.eclipse.persistence.descriptors
パッケージに含まれています。
EclipseLinkディスクリプタには次の情報を格納できます。
ディスクリプタ自体の中で記述する永続Javaクラス、および対応するデータ・ソース(データベース表またはXMLの複合型インタラクション)。
そのクラスの属性とリレーションシップをデータ・ソースでどのように表現するかを記述したマッピングのコレクション。
データ・ソースの主キー情報(またはそれに相当する情報)。
フィールド名の問合せキー(または別名)のリスト。
順序番号の情報。
ディスクリプタの動作を調整するためのオプション・プロパティのセット。リフレッシュ・オプションのキャッシング、アイデンティティ・マップ、オプティミスティック・ロック、イベント・マネージャおよび問合せマネージャに関するサポートが含まれます。
EclipseLinkがサポートするデータ・ソース・タイプごとに、対応するディスクリプタ・タイプがあります。同一のデータ・ソース・タイプに対して有効なディスクリプタ・タイプが複数ある場合もあります。使用するディスクリプタのタイプにより、定義できるマッピングのタイプが決まります。
継承とは、導出されたクラス(子)にそのスーパークラス(親)の特性をどのように受け継がせるかを意味します。ディスクリプタを使用すると、リレーショナル・プロジェクトおよびXMLプロジェクトにおいてクラス間の継承リレーションシップを定義できます。
子クラスのディスクリプタでは、親クラスのディスクリプタに指定されているマッピングをオーバーライドしたり、親クラスのディスクリプタにマップされていない属性をマップできます。
図5-1は、Java継承階層の代表例としてVehicle
というオブジェクト・モデルを示します。ルート・クラスのVehicle
には、2つブランチ・クラスFueledVehicle
およびNonFueledVehicle
が含まれています。各ブランチ・クラスには、それぞれCar
およびBicycle
というリーフ・クラスが含まれます。
EclipseLinkが継承階層で認識するクラスは、次の3つの種類です。
ルート・クラスは、サブクラス階層内のすべてのインスタンス化可能クラスの情報を格納します。デフォルトでは、ルート・クラスに対して実行された問合せにより、ルート・クラスおよびインスタンス化可能なサブクラスのインスタンスが返されます。ただし、ルート・クラスの構成方法によっては、ルート・クラスに対する問合せ時にサブクラスのインスタンスを省いて、ルート・クラス自体のインスタンスのみを返すこともできます。
たとえば、図5-1のVehicle
クラスが、ルート・クラスです。
ブランチ・クラスは、永続スーパークラスの他にサブクラスを持つものです。デフォルトでは、ブランチ・クラスに対して実行された問合せにより、ブランチ・クラスおよびそのサブクラスのインスタンスが返されます。ただし、ルート・クラスの場合と同様に、ブランチ・クラスの構成方法によっては、ブランチ・クラスに対する問合せ時にサブクラスのインスタンスを省いて、ブランチ・クラス自体のインスタンスのみを返すこともできます。
たとえば、図5-1のFueledVehicle
クラスが、ブランチ・クラスです。
リーフ・クラスには、階層内の永続スーパークラスがありますが、サブクラスはありません。リーフ・クラスに対して実行された問合せにより、リーフ・クラスのインスタンスのみが返されます。
たとえば、図5-1のCar
クラスが、リーフ・クラスです。
子クラスのディスクリプタでは、親クラスのディスクリプタに指定されているマッピングをオーバーライドしたり、親クラスのディスクリプタにマップされていない属性をマップできます。
この項では、次の内容について説明します。
継承を構成する場合は、ルート・クラス・ディスクリプタに、インスタンス化先のサブクラスの選択の方法を構成します。
これを行うには、次のいずれかの方法を実行します。
注意: 継承階層内のすべてのリーフ・クラスにはクラス・インジケータが必須で、かつこれらのリーフ・クラスは同じタイプのクラス・インジケータ(フィールドまたはクラス抽出メソッド)を持つ必要があります。 |
クラスの永続属性を使用すると、インスタンス化先のサブクラスを指定できます。たとえば、リレーショナル・ディスクリプタでは、ルート・クラス表のクラス・インジケータ・フィールドを使用できます。ただし、クラス・インジケータ・フィールドには、読取り専用に設定されていないダイレクト・マッピングを関連付けないでください。
注意: インジケータ・フィールドが主キーの一部である場合は、インジケータ・フィールドに対する書込み専用トランスフォーメーション・マッピングを定義します。 |
クラス・インジケータ・フィールドでは、値として文字列または数値を使用できます。
ルート・クラス・ディスクリプタによって、クラス・インジケータ・フィールドの値をインスタンス化されるクラスに変換する方法を指定する必要があります。
オブジェクトのデータ・ソース・レコード内で利用可能なすべての情報に基づいて、クラス・インジケータを計算するJavaメソッドを定義することができます。このようなメソッドをクラス抽出メソッドといいます。
クラス抽出メソッドを使用すると、データ・モデルに明示的なクラス・インジケータ・フィールドを含める必要がなくなり、また、複雑すぎてクラス・インジケータ・フィールドには定義できないリレーションシップを処理できます。
クラス抽出メソッドには次の特性が必要です。
ルート・ディスクリプタのクラスをベースにして定義されていること
静的であること
引数としてRecord
をとること
入出力引数であるRecord
にjava.lang.Class
オブジェクトを出力すること
状況に応じて、only-instancesおよびwith-all-subclasses式も定義する必要があります。クラス抽出メソッドを使用する場合は、共通の表を使用するすべてのクラスの兄弟インスタンスを正しくフィルタ処理するための式を、EclipseLinkに指定する必要があります。
クラス抽出メソッドを使用して継承を構成した場合、EclipseLinkではルート・クラスに関する問合せのためのSQLは生成されません。
リレーショナル・プロジェクトの場合、EclipseLinkでは、継承階層内のすべてのクラスが、ルート・ディスクリプタに設定されているのと同じ主キーを持っていることが前提とされます。
リレーショナル・プロジェクトでは、継承階層を単一の表または複数の表にマップできます。
リレーショナル・ディスクリプタを集約ディスクリプタとして指定できます。XMLディスクリプタは常にコンポジット・ディスクリプタです(5.1.3項「ディスクリプタと集約」を参照)。
リレーショナル集約ディスクリプタで継承を構成する場合は、継承ツリー内のすべてのディスクリプタが集約である必要があります。つまり、集約クラスと非集約クラスのディスクリプタを同じ継承ツリーに置くことはできません。
XMLディスクリプタで継承を構成する場合は、すべてのXMLディスクリプタがコンポジットであるため、継承はディスクリプタ・タイプによる制限を受けません。
2つのオブジェクト、つまり、ソース(親、すなわち所有)オブジェクトとターゲット(子、すなわち被所有)オブジェクトは、両者間に厳密な1対1の関係がある場合、集約によって関連付けられ、ターゲット・オブジェクトのすべての属性は、ソース・オブジェクトと同じデータ・ソース表現から取得できます。つまり、ソース・オブジェクトが存在すればターゲット・オブジェクトも存在する必要があり、ソース・オブジェクトが破棄されればターゲット・オブジェクトも破棄されるということです。
この場合、ソースおよびターゲット・オブジェクトのディスクリプタは、この関係を反映するよう定義する必要があります。
EJB 3.0仕様はネストされた集合をサポートしていません。
ディスクリプタ・カスタマイザを指定すると、実行時にディスクリプタをカスタマイズできます。ディスクリプタ・カスタマイザはJavaクラスの1つで、org.eclipse.persistence.config.DescriptorCustomizer
インタフェースを実装し、デフォルト(ゼロ引数)・コンストラクタを備えています。
ディスクリプタ・カスタマイザを使用することで、コードAPIを介して実行時にディスクリプタがカスタマイズされますが、その方法は、修正メソッドを使用してディスクリプタをカスタマイズする方法と類似しています。5.1.5項「修正メソッド」を参照してください。
実行時にディスクリプタがロードされるときにコールするstatic Javaメソッドを関連付けることができます。このメソッドは、ディスクリプタのJavaコードAPIを介して実行時のディスクリプタ・インスタンスを修正できます。このメソッドは、public
static
であり、タイプorg.persistence.descriptors.structures.ClassDescriptor
の属性を1つとるものである必要があります。このメソッドの実装では、publicの任意のディスクリプタとマッピングAPIを使用して、ディスクリプタの高度な機能を構成できます。
ただし、ディスクリプタはセッションが接続される前にのみ修正できます。これは、セッションの接続後にディスクリプタを修正するのは望ましくないためです。
修正メソッドは、有理数型ディスクリプタ、オブジェクト・リレーショナル・データ・タイプのディスクリプタ、およびXMLディスクリプタとともに使用できます。
リレーショナル・プロジェクトでは、EclipseLinkによって、永続性のライフ・サイクル中にDescriptorEvent
の様々なインスタンスが起動されます。各ディスクリプタは、これらのイベントを受信してそれを登録済のディスクリプタ・イベント・ハンドラにディスパッチする役割を持つDescriptorEventManager
のインスタンスを所有します。
ディスクリプタ・イベント・ハンドラを使用すると、構築したアプリケーション固有のロジックをディスクリプタ・イベントの発生時に実行でき、永続データのライフ・サイクルの様々な時点において実行可能なカスタマイズ・アクションをとれるようになります。たとえば、ディスクリプタ・イベント・ハンドラを使用して次の動作を実行できます。
永続オブジェクトと他のシステム、サービスおよびフレームワークとの同期化
EclipseLinkで対応していない非永続属性の管理
オブジェクトの永続状態が変化したときにアプリケーションの他のオブジェクトに通知すること
EclipseLinkのマッピングで直接サポートされていない複雑なマッピングまたは最適化を実装すること
次の項では、オブジェクト・リレーショナル・ディスクリプタに固有の概念について説明します。
デフォルトでは、特定のオブジェクト・クラスに対してオブジェクト・レベルの読取り問合せを実行すると、そのオブジェクトのディスクリプタにマップされているすべての永続属性がEclipseLinkによって返されます。この1回の問合せを実行するだけで、対象オブジェクトのすべての永続属性が定義され、さらに、各属性のget
メソッドをコールすることで、属性値をオブジェクトから直接取得できます。
オブジェクトの属性の一部のみが必要な場合は、フェッチ・グループを使用して、そのオブジェクトの属性のサブセットのみが返されるようにした方が効率的です。
フェッチ・グループを使用して、オブジェクトの属性のサブセットを定義し、そのフェッチ・グループをReadObjectQuery
またはReadAllQuery
問合せと関連付けることができます。問合せを実行すると、EclipseLinkによりフェッチ・グループ内の属性のみが取得されます。除外された属性のいずれかに関するgetメソッドをコールすると、EclipseLinkでは、このサブセットから除外されたすべての属性をフェッチする問合せが自動的に実行されます。
1つのクラスに対して複数のフェッチ・グループを定義できます。オプションで、デフォルトのフェッチ・グループとして最大1つのフェッチ・グループを指定できます。フェッチ・グループを指定しないでReadObjectQuery
またはReadAllQuery
問合せを実行する場合、問合せを別の方法で構成しないかぎり、EclipseLinkではデフォルトのフェッチ・グループが使用されます。
フェッチ・グループを使用する前に、システムの使用状況を綿密に分析しておくことをお薦めします。多くの事例では、フェッチ・グループに含まれない属性をロードするために必要な追加の問合せにより、部分的な属性のロードによって得られるメリットがかなり相殺されているためです。
フェッチ・グループは、FetchType.LAZY (partial object queries)
で構成された基本マッピングとのみ組み合せて使用できます。
EclipseLinkでは、フェッチ、ロード、コピーおよびマージ操作で部分的エンティティの使用を構成するために使用できるAttributeGroup
を使用します。
フェッチ: データベースから取得される属性とその関連列を制御します。
ロード: 問合せから返されたエンティティで移入されるリレーションシップを制御します。
コピー: 新しいエンティティ・インスタンスにコピーされる属性を制御します。
マージ: エンティティにフェッチ、ロードまたはコピーされた属性のみをマージします。
FetchGroup
は、問合せ実行の結果としてエンティティが取得されるときにフェッチする(データベースから選択する)必要のある属性を定義します。FetchGroup
にリレーションシップ属性を含めることで決定されるのは、属性の必須列をフェッチして移入するかどうかのみです。遅延フェッチ・タイプの場合、属性を含めることで、そのプロキシが作成されてアクセス時に遅延ロードが有効になります。問合せでのFetchGroup
の使用時にリレーションシップ・マッピングの移入を強制するには、属性をグループに含め、FetchType.EAGER
に設定するか、問合せで関連するLoadGroup
に含める必要があります。
FetchGroup
には、FetchGroupManager
によって管理される名前付きのデフォルトFetchGroup
の概念も含まれます。デフォルトFetchGroup
は、1つ以上の基本マッピングが遅延するように構成され、エンティティ・クラスがFetchGroupTracker
を実装している場合に、メタデータ処理中に定義されます(通常はウィービングを通じて導入されます)。デフォルトFetchGroup
は、明示的FetchGroup
や名前付きFetchGroup
が構成されていないこのエンティティ・タイプのすべての問合せで使用されます。
名前付きFetchGroup
は、@FetchGroup
注釈を使用して、またはeclipselink-orm.xml
ファイル内で、エンティティに対して定義できます。
FetchGroup
は、最初に作成されたときは空であると想定されます。ユーザーは、FetchGroup
に属性を追加する必要があります。すべての属性を含むFetchGroup
が必要な場合、FetchGroupManager.createFullFetchGroup()
を使用する必要があります。
FetchGroup
は、リレーションシップ・マッピングやネストしたリレーションシップ・マッピングのロード操作を実行するように構成することもできます。
LoadGroup
を使用して、リレーションシップ属性の指定したセットに問合せ結果での移入を強制します。
CopyGroup
によって、エンティティのコピー方法を定義するために使用される、非推奨のObjectCopyPolicy
が置換されます。ソース・エンティティ・グラフからターゲット・コピーにコピーする内容を定義する属性を指定することに加え、CopyGroup
では次の定義も可能です。
shouldResetPrimaryKey
: 識別子属性をデフォルト値にリセットします。これは、コピー操作でソースと同様の状態の新しいエンティティを作成するためにエンティティをクローニングする場合に使用されます。デフォルトはfalse
です。
shouldResetVersion
: オプティミスティック・バージョンのロック属性をコピーでデフォルト値にリセットします。デフォルトはfalse
です。
depth
: リレーションシップを処理するためのカスケード・モードを定義します。デフォルトでは、CASCADE_PRIVATE_PARTS
が使用されますが、NO_CASCADE
やCASCADE_ALL_PARTS
にも構成できます。
使用可能な属性を定義して、部分エンティティをAttributeGroup
が関連付けられた永続性コンテキストにマージすると、それらの属性のみがマージされます。エンティティ内のリレーションシップ・マッピングも、それらのカスケード・マージ設定に従ってマージされます。
各リレーショナル・ディスクリプタには、次の構成に使用できるDescriptorQueryManager
のインスタンスが用意されています。
名前付き問合せ
基本的な永続性操作用のカスタムのデフォルト問合せ
追加の結合式
オブジェクト・アイデンティティを保持するうえで重要なのは、各オブジェクト・インスタンスを区別するために一意の値(特定の順序)の割当てを管理することです。
順序付けオプションにプロジェクト・レベルとセッション・レベルのいずれを構成するかにより、EclipseLinkで使用される順序付けのタイプが決まります。POJOプロジェクトの場合、セッション・レベルの順序構成を使用して、プロジェクト・レベルの順序構成をセッション単位でオーバーライドすることもできます。
順序タイプの構成後、ディスクリプタの参照クラスごとに、1つの属性(通常は主キーとして使用する属性)を独自の順序に関連付ける必要があります。
オブジェクト・リレーショナル・マッピングでは、次に示すロック・ポリシーのいずれかを使用してディスクリプタを構成し、ドメイン・オブジェクトへの同時アクセスを制御できます。
オプティミスティック: すべてのユーザーにデータへの読取りアクセス権限があります。ユーザーが変更を加えようとした場合、そのユーザーがデータを読み取った後にデータが変更されていないか、アプリケーションによってチェックされます。
ペシミスティック: 更新目的でデータにアクセスした最初のユーザーによって、更新処理が完了するまでデータがロックされます。
ロックなし: 複数のユーザーが互いの変更内容を上書きする操作は阻止されません。
ほとんどのタイプのアプリケーションでは、ユーザー同士が互いの変更内容を上書きできないようにするために、オプティミスティック・ロックを使用することをお薦めします。
この項では、EclipseLinkでサポートされている次のような様々なタイプのロック・ポリシーについて説明します。
オプティミスティック・ロックを使用した場合、すべてのユーザーにデータへの読取りアクセス権限があります。ユーザーが変更を加えようとした場合、そのユーザーがデータを読み取った後にデータが変更されていないか、アプリケーションによってチェックされます。
オプティミスティック・バージョン・ロック・ポリシーでは、バージョン・フィールド(書込みロック・フィールド)を使用して、オプティミスティック・ロックが実行されます(バージョン・フィールドは、参照クラス内に作成し、オブジェクト変更がコミットされるたびにEclipseLinkによって更新されます)。
EclipseLinkは、データ・ソースからオブジェクトを読み取るときにこのバージョン・フィールドの値をキャッシュします。クライアントがオブジェクトに書き込もうとすると、EclipseLinkはキャッシュしたバージョン値とデータ・ソース内の最新のバージョン値を次のように比較します。
2つの値が一致した場合は、EclipseLinkはオブジェクト内のバージョン・フィールドを更新し、データ・ソースに対する変更内容をコミットします。
2つの値が一致しなかった場合は、そのクライアントが最初にオブジェクトを読み取った後に別のクライアントがそのオブジェクトを更新したことを意味するため、書込み操作を却下します。
EclipseLinkには、次のようなバージョン・ベースのオプティミスティック・ロック・ポリシーが用意されています。
VersionLockingPolicy
TimestampLockingPolicy
これらのロック・ポリシーの詳細は、Oracle TopLinkのソリューション・ガイドのオプティミスティック・ロックの設定に関する項を参照してください。
注意: 次の理由から、通常はnumericタイプのバージョンのロックをお薦めします。
|
オプティミスティック・ロック違反により更新が失敗すると、EclipseLinkではOptimisticLockException
がスローされます。この例外は、データベースの変更を行っているアプリケーションで処理する必要があります。アプリケーションは、ロックの競合をクライアントに通知し、オブジェクトをリフレッシュして、クライアントに変更内容の再適用を依頼する必要があります。
バージョン値は、オブジェクト内にマップ済属性として格納するか、キャッシュに格納するかを選択できます。3層アプリケーションでは、オブジェクトの更新時にバージョン値が確実にクライアントに渡されるようにするため、オブジェクト内にバージョン値を格納しておく方法が一般的です(5.2.4.3項「アプリケーションでのロックの適用」を参照)。
バージョン値をキャッシュに格納する場合、バージョン値のマッピングは必要ありません。バージョン・フィールドをマップする場合、マッピングを読取り専用として構成する必要があります。
私有の子オブジェクトの変更時にその親オブジェクトのバージョン・フィールドが確実に更新されるようにするには、5.2.4.1.1項「オプティミスティック・バージョン・ロック・ポリシーとカスケード」を使用することを検討します。
ストアド・プロシージャを使用してオブジェクトを更新または削除する場合、オプティミスティック・ロックの障害を検出するために必要な行数をデータベースが返さないことがあるため、ストアド・プロシージャでオプティミスティック・ロックのバージョンを確認し、一致しない場合はエラーをスローする必要があります。StoredProcedureCall
では、バージョン・ロックのみが直接サポートされます。タイムスタンプおよびフィールド・ロックでは、同じフィールドの2つのバージョンをコールに渡す必要があるため、##
パラメータを使用してトランザクション行にアクセスするSQLコールは、他のロック・ポリシーに使用できます。
使用するデータベース・スキーマが、親オブジェクトおよびその私有の子オブジェクトの両方を同じ表内に格納する設計になっている場合には、その子オブジェクトを更新すると、親オブジェクトのバージョン・フィールドが更新されます。
一方、親オブジェクトおよびその私有の子オブジェクトを異なる表に格納する場合は、デフォルトでは、子を変更しても、親のバージョン・フィールドは更新されません。
この場合に親オブジェクトのバージョン・フィールドを確実に更新するには、親オブジェクトのバージョン・フィールドを手動で更新するか、またはVersionLockingPolicy
を使用している場合は、子オブジェクトのバージョン・フィールドの更新が親に自動的にカスケードされるようにEclipseLinkを構成することができます。
オプティミスティック・バージョン・ロックのカスケード機能を有効化した場合に、私有の子オブジェクトを変更すると、EclipseLinkはその私有されている外部参照マッピングを走査し、ルートに向かってすべての親オブジェクトを更新します。
EclipseLinkでは、次の場合にオプティミスティック・バージョン・ロックのカスケードがサポートされます。
私有の1対1および1対多マッピングでのオブジェクト変更
次のコレクション・マッピング(私有かどうかは問わない)でのリレーションシップ変更(追加または削除)
ダイレクト・コレクション
1対多
多対多
集約コレクション
図5-2に例示したオブジェクトの図について考えてみます。
この例では、ObjectA
がObjectB
を私有し、ObjectB
はObjectC
を私有し、ObjectC
はObjectD
を私有します。
ObjectB
を作業ユニットに登録し、ObjectB
を変更して、作業ユニットをコミットしたとします。この場合、ObjectB
はObjectA
のキャッシュをチェックし、値が存在しない場合にはデータベースに対してObjectA
を問い合せます。次に、ObjectB
は自身の変更をObjectA
に通知します。ObjectA
は、自身に対応する表に変更がない場合でも、自身のバージョン・オプティミスティック・ロック・フィールドを更新します。
ObjectA
を作業ユニットに登録し、そのObjectB
、ObjectC
、ObjectD
にこの順序でアクセスして、ObjectD
のフィールドを変更し、作業ユニットをコミットするとします。この場合は、ObjectD
が自身の変更をObjectC
に通知します。ObjectC
は、自身に対応する表に変更がない場合でも、自身のバージョン・オプティミスティック・ロック・フィールドを更新します。次に、ObjectC
はObjectD
の変更をObjectB
に通知します。次に、ObjectB
がObjectD
の変更をObjectA
に通知します。ObjectA
は、自身に対応する表に変更がない場合でも、自身のバージョン・オプティミスティック・ロック・フィールドを更新します。
オプティミスティック・ロックで、オプティミスティック・ロックのバージョンをキャッシュに格納する場合、ロックされたオブジェクトの値をロールバックするにはUnitOfWork
メソッドcommitAndResumeOnFailure
を使用します。
ロックされた複数のバージョンを1つのオブジェクトに格納する場合は、更新失敗時に各オブジェクト(すなわち、オブジェクトのバージョン)をリフレッシュする必要があります。あるいは、失敗時に新しい作業ユニットを取得して、そのユニットに変更を再適用することもできます。
オプティミスティック・フィールド・ロック・ポリシーでは、表内に現存する1つ以上のフィールドを使用して、クライアントが対象オブジェクトを読み取った以後にそのオブジェクトが変更されたかどうかを判別することによって、オプティミスティック・ロックが実行されます。
ユーザーがオブジェクトを最初に読み取ったとき、またはオブジェクトを作業ユニットに登録したときに、作業ユニットにより、そのオブジェクトの元の状態がキャッシュされます。コミット時には、ロック・フィールドの元の値と更新中のデータ・ソースの現在の値が、作業ユニットにより比較されます。ロック・フィールドのいずれかの値が変更されていた場合には、オプティミスティック・ロック例外がスローされます。
EclipseLinkには、次のようなオプティミスティック・フィールド・ロック・ポリシーが用意されています。
AllFieldsLockingPolicy
ChangedFieldsLockingPolicy
SelectedFieldsLockingPolicy
VersionLockingPolicy
TimestampLockingPolicy
これらのロック・ポリシーの詳細は、Oracle TopLinkのソリューション・ガイドのオプティミスティック・ロックの設定に関する項を参照してください。
ペシミスティック・ロックを使用した場合は、データを更新する目的でそのデータにアクセスする最初のユーザーが、更新を完了するまでデータをロックします。
ペシミスティック・ロック・ポリシーを使用する場合は、更新をただちに失敗させるか、読取りロックが取得されるまで待機させるようにポリシーを構成できます。
ペシミスティック・ロック・ポリシーは、コンテナ管理の永続性タイプと、EJB情報を含むディスクリプタを保持するプロジェクトでのみ使用できます。
(ペシミスティック・ロック・ポリシーではなく)ペシミスティック・ロックは、問合せレベルでも使用できます。
EclipseLinkでは、ペシミスティック・ロックをコンテナ管理の永続性を持つエンティティとともに使用する場合にこのロックの最適化が行われ、問合せをペシミスティック・ロックに設定し、(ファインダの実行後に終了する)独自の新しいトランザクションで問合せを実行すると、EclipseLinkによってそのロック設定はオーバーライドされ、SQLにFOR UPDATE
は追加されません。ただし、ユーザーがFOR
UPDATE
を含むSQL文字列でペシミスティック・ロック問合をカスタマイズしている場合、この最適化の使用によって不都合な結果が発生する可能性があります。この場合、最適化が必要な状況が存在すると、問合せは非ペシミスティック・ロックにリセットされますが、SQLは同じままのため、問合せのロック設定が問合せのSQL文字列と競合します。この問題を回避するには、次の2つのアプローチのいずれかを使用します。
選択基準として式を使用します(第10章「EclipseLinkの式の理解」)。これによって、EclipseLinkでSQLの生成を制御します。
最適化の条件をなくすため、ファインダをトランザクション内に配置します。
アプリケーションで適切にオブジェクトをロックするには、オブジェクトが編集のためにクライアントに送信される前に、ロックを取得する必要があります。
オプティミスティック・ロックを使用する場合、オブジェクトを正しくロックするには次の2つの選択肢があります。
オブジェクト内のオプティミスティック・ロック・フィールドを読取り専用以外にマップし、読取り時にバージョンをクライアントに渡し、更新時にサーバーに戻します。
更新のためにオブジェクトが読み取られるときに、元のバージョン値がクライアントに送信されることを確認します。クライアントは、その元のバージョン値を更新情報とともに戻す必要がありますが、このバージョンは、サーバー上の新しい作業ユニットで登録または読取りが行われた後に、更新対象のオブジェクトに設定される必要があります。
クライアントとの対話が完了するまで作業ユニットを保持します。
ステートフル・セッションBeanを介して、またはHTTPセッションにおいて、更新対象オブジェクトの読取りに使用する作業ユニットを、クライアントとの対話が完了するまで保管します。
オブジェクトをクライアントに更新用に渡す前に、この作業ユニットからオブジェクトを読み取っておく必要があります。これにより、作業ユニットのキャッシュまたは作業ユニットのクローンに元のバージョン値を保管しておけます。
この同じ作業ユニットを更新でも必ず使用します。
1番目の選択肢の方が一般的に使用され、ステートレス・アプリケーションを開発する場合には必須となります。
次の項では、オブジェクト・リレーショナルおよびMOXyマッピングに使用できるディスクリプタ・ファイルについて説明します。
orm.xml
ファイルを使用して、メタデータを永続性ユニットに適用します。このメタデータは、すべてのマッピング・ファイルと注釈の集合です(xml-mapping-metadata-complete
要素が存在しない場合)。メタデータに対して1つのマッピングorm.xml
ファイルを使用し、そのファイルをクラスパスのMETA-INF
ディレクトリに配置する場合、それを明示的にリストする必要はありません。このファイル(orm.xml
)は、永続性プロバイダによって自動的に検索され、使用されます。
JPA 2.0 orm.xml
のスキーマは、orm_2_0.xsd
です。(http://java.sun.com/xml/ns/persistence/orm_2_0.xsd
)
マッピング・ファイルを異なる名前で使用するか、異なる場所に配置する場合、それらをpersistence.xml
ファイルのmapping-file
要素にリストする必要があります。
EclipseLinkは、eclipselink-orm.xml
という拡張JPA orm.xml
マッピング構成ファイルをサポートしています。このマッピング・ファイルは、JPAの標準マッピング・ファイルのかわりとして、またJPAのマッピング・ファイルをオーバーライドするためにも使用できます。すべての標準JPAマッピング機能を使用できるだけでなく、高度なマッピング・タイプとオプションも使用できます。
eclipselink-orm.xml
ファイルの詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のeclipselink-orm.xmlのスキーマ参照に関する項を参照してください。
注意: このマッピング・ファイルを使用すると、EclipseLinkの多くの高度な機能が有効になりますが、他のJPA実装に対する永続性ユニットの移植性がなくなる場合があります。 |
オーバーライド値の詳細は、次を参照してください。
JPA仕様の「XML Overriding Rules」
eclipselink-orm.xml
のスキーマはeclipselink_orm_2_2.xsd
です。
http://www.eclipse.org/eclipselink/xsds/eclipselink_orm_2_2.xsd
orm.xml
ファイルのマッピングをオーバーライドするには、プロジェクトでMETA-INF/eclipselink-orm.xml
ファイルを定義する必要があります。eclipselink-orm.xml
の内容が、orm.xml
および永続性ユニットで指定されたその他のJPAマッピング・ファイルをオーバーライドします。複数のORMファイルの指定が重複している場合、競合エンティティが存在しなければそれらのファイルはマージされます。
詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のオーバーライドおよびマージに関する項を参照してください。
デフォルトでは、.orm
XMLファイルの内容は、JPAの.orm
XMLスキーマに対して検証されません。
開発時に、.orm
XMLファイルをスキーマに対して検証し、その妥当性を確認することをお薦めします。EclipseLinkで.orm
XMLスキーマの検証を有効にするには、persistence.xml
ファイルの永続性ユニット・プロパティeclipselink.orm.validate.schema
を使用します。
Java注釈を使用して、プロジェクトにJAXBの機能を指定できます。EclipseLinkには、Java注釈に加えて、eclipselink-oxm.xml
というXMLマッピング構成ファイルが用意されています。このマッピング・ファイルには、標準のJAXBマッピングと、高度なマッピング・タイプ用の構成オプションが含まれています。eclipselink-oxm.xml
ファイルを、ソース・コードのJAXB注釈のかわりに使用するか、JAXB注釈をオーバーライドするために使用できます。
注意: このマッピング・ファイルを使用すると、多くの高度な機能が有効になりますが、他のJAXB実装に対するモデルの移植性がなくなる場合があります。 |