| Oracle® Fusion Middleware Oracle WebLogic Server Enterprise JavaBeansバージョン2.1のプログラミング 12cリリース1(12.1.1) B65951-02 |
|
![]() 前 |
![]() 次 |
この章では、アプリケーションでエンティティBeanをプログラミングおよび使用するためのWebLogic Serverの付加価値機能について説明し、関連する設計および開発上のガイドラインを示します。
この章は、JavaのプログラミングおよびエンティティBeanの機能に精通している読者を対象としています。エンティティBeanの概要およびエンティティBeanのアプリケーションでの典型的な使用方法については、「エンティティEJBによる永続データの保持」および「エンティティBeanの機能」を参照してください。
Bean開発の全体的なプロセスについては、「Enterprise JavaBeansの実装」を参照してください。
WebLogic Serverには、エンティティEJBのパフォーマンスとスループットを向上させる以下の機能があります。
フリー・プール - ファインダ、ホーム・メソッドの呼び出し、およびエンティティBeanの作成に使用する匿名エンティティBeanを格納します。
キャッシュ - ID (主キー)を持つインスタンス、またはトランザクションに現在登録されているインスタンスを格納します(READYおよびACTIVEのエンティティEJBインスタンス)。
図6-1は、エンティティBeanインスタンスのライフサイクルを示しています。この節では、プール処理について、およびコンテナがフリー・プールとキャッシュにデータを格納して管理する仕組みについて説明します。
weblogic-ejb-jar.xmlでinitial-beans-in-free-pool要素にゼロ以外の値を指定すると、WebLogic Serverは起動時に指定された量のBeanインスタンスをプールに格納します。
initial-beans-in-free-poolのデフォルト値はゼロです。起動時にBeanインスタンスをフリー・プールに格納しておくと、要求が来てから新しいインスタンスを生成せずにBeanに対する初期要求が可能になるため、EJBの初期応答時間が短縮されます。このリリースのWebLogic Serverでは、管理者は管理コンソールを使用してプールを必要に応じて初期化できます。初期化されたプールは、EJBがデプロイされた直後の状態にリセットされます。詳細は、Oracle WebLogic Server管理コンソール・オンライン・ヘルプのEJBのアイドル状態のBeanのキャッシュおよびプールの初期化に関する項を参照してください。
フリー・プールからエンティティBeanのインスタンスを取得しようとすると、その試みはプールが空の場合でも必ず成功します。プールが空の場合は、新しいBeanインスタンスが作成されて返されます。
プールされたBeanは匿名インスタンスであり、ファインダおよびホーム・メソッドで使用されます。プールに格納できるインスタンスの最大数は、weblogic-ejb-jar.xmlのmax-beans-in-free-pool要素で指定します(デフォルト設定は1,000)。
WebLogic Serverを構成することによって、プール内のエンティティBeanがpool要素のidle-timeout-seconds要素で指定した期間にわたって未使用であった場合にそのBeanを削除できます。idle-timeout-secondsで指定する期間にわたってプール内のBeanが未使用である場合、そのプール内のBeanはinitial-beans-in-free-poolで指定されている数まで削除されます。プール内のBeanの数は、initial-beans-in-free-poolで指定されている数より少なくなることはありません。
Beanでビジネス・メソッドが呼び出されると、コンテナはプールからインスタンスを取得し、ejbActivateを呼び出して、そのインスタンスがメソッド呼出しに対応します。
READYインスタンスはキャッシュにあり、ID (関連付けられた主キー)を持ちますが、現時点ではトランザクションに登録されていません。READYエンティティEJBのインスタンスは、最長時間未使用(LRU)の順で維持されます。
ACTIVEインスタンスは、現時点でトランザクションに登録されています。トランザクションの完了後、そのインスタンスはREADYになり、他のBean用にスペースが必要になるまでキャッシュにとどまります。
管理コンソールの「モニター」タブの「現在のキャッシュ済みBean数」フィールドには、READYおよびACTIVE Beanの数が表示されます。また、このリリースのWebLogic Serverでは、管理者は管理コンソールを使用してキャッシュを必要に応じて初期化できます。初期化されたキャッシュは、EJBがデプロイされた直後の状態にリセットされます。詳細は、Oracle WebLogic Server管理コンソール・オンライン・ヘルプのEJBのアイドル状態のBeanのキャッシュおよびプールの初期化に関する項を参照してください。
max-beans-in-cache要素の効果とキャッシュで許可される主キーが同じインスタンスの数は、同時実行性ストラテジによって異なります。表6-1は、同時実行性ストラテジごとに、weblogic-ejb-jar.xmlのmax-beans-in-cache要素の値がキャッシュ内のエンティティBeanインスタンスの数をどのように制限するのか、および同じ主キーでエンティティBeanインスタンスがいくつキャッシュ内で許可されるのかを示しています。
表6-1 同時実行性タイプ別のエンティティEJBのキャッシング動作
| 同時実行性オプション | キャッシュ内のBeanインスタンス数に対するmax-beans-in-cacheの影響 | 主キーの同じインスタンスが同時にいくつキャッシュに存在できるか |
|---|---|---|
|
|
|
1 |
|
|
|
複数 |
|
|
|
1 |
READYのエンティティEJBインスタンスは、他のBeanでスペースが必要なときにキャッシュから削除されます。READYインスタンスがキャッシュから削除され、BeanでejbPassivateが呼び出されて、コンテナがそのインスタンスをフリー・プールに戻そうとします。
WebLogic Serverを構成することによって、キャッシュ内のエンティティ・インスタンスがidle-timeout-seconds要素で指定した期間にわたってアイドル状態である(トランザクションに参加していない)場合にそのインスタンスを定期的に削除できます。専用キャッシュの場合、クリーニング・タスクの固定期間はidle-timeout-secondsの値に等しくなります。アプリケーション・レベルのキャッシュの場合、複数のタイプのエンティティBeanがキャッシュを共有し、各Beanがそれぞれのidle-timeout-secondsの値を使用できるようになります。この場合、クリーニング・タスクの固定期間はMIN(キャッシュ内のすべてのBeanのidle-timeout-secondsのセット)に等しくなり、クリーニング・タスクは可変期間で実行される可能性があります。
コンテナがインスタンスをフリー・プールに戻そうとしたときに、プールがすでにmax-beans-in-free-pool数のインスタンスで満たされている場合、インスタンスは破棄されます。
ACTIVEのエンティティEJBインスタンスは、そのインスタンスが参加しているトランザクションがコミットまたはロールバックされるまでキャッシュから削除されません。トランザクションがコミットまたはロールバックされた時点で、インスタンスはREADYになり、キャッシュから削除できるようになります。
満杯であるキャッシュにエンティティBeanが追加されようとしたときに、トランザクションに参加しているエンティティBeanは、必要な場合、CacheFullExceptionを回避するためにパッシブ化することができます。パッシブ化はEJBコンテナによって自動処理されるため、この機能を使用するためにEJBのプログラミングを変更する必要はありません。しかし、必要な場合、EJBが現在のトランザクション内のすべての操作を実行したことをキャッシュに伝えるようにプログラミングできます。この場合、キャッシュはBeanのパッシブ化が可能かどうかを評価するときにこの情報を利用します。
EJBが現在のトランザクション内のすべての操作を実行したことをキャッシュに伝えるようにプログラミングするには、次のようにoperationsComplete Java APIを使用します。
weblogic.ejb.interfaces.EJBLocalObject public.void.operationsComplete() weblogic.ejb.EJBObject public.void.operationsComplete()
この節では、CMP 2.1エンティティBeanの永続データがいつどのようにしてキャッシュにロードされ、永続ストレージに書き込まれるのかを説明します。
findXXX() - デフォルトでは、CMP Beanでファインダ・メソッドを呼び出すと、Beanの永続データがすぐにキャッシュにロードされます。この動作は、weblogic-ejb-jar.xmlのpersistence要素のfinders-load-bean要素で制御します。
ejbLoad() - CMP 2.1エンティティBeanの場合は、ejbLoad()を呼び出すと、Beanのデータに対して次にgetXXX()が呼び出されたときにBeanの永続データがエンティティ・キャッシュに「怠惰」にロードされます。したがって、CMP 2.0エンティティBeanのインスタンスでトランザクションが開始されるときは、Beanが最後にキャッシュにロードされてからejbLoad()が呼び出されていない限り、WebLogic Serverはデータベースからではなくエンティティ・キャッシュからBeanのデータを読み込みます。
デフォルトでは、WebLogic ServerはエンティティBeanで新しいトランザクションが開始されるたびにejbLoad()を呼び出します。
|
注意: CMP 1.1のエンティティBeanおよびBean管理による永続性を使用するエンティティBeanで使用する場合、 |
ejbStore() - WebLogic Serverは、ejbStore()の呼出しを使用してエンティティEJBの永続フィールドをデータベースに書き込みます。
デフォルトでは、WebLogic Serverはトランザクションのコミット時にejbStore()を呼び出します。
複数のクライアントがBeanの基底データにアクセスして修正できるアプリケーションの場合、「ejbLoad()とejbStore()の動作について」で説明されているejbLoad()とejbStore()のデフォルトの動作では、以下のようにしてデータベースの整合性が確保されます。
新しいトランザクションがそれぞれEJBの永続データの最新バージョンを必ず使用するようにする
トランザクションのコミット時にデータベースを更新する
ただし、要件によっては、ejbLoad()およびejbStore()の呼出し回数を増やすか減らす必要があるかもしれません。たとえば、パフォーマンス上の理由から、データベースにアクセスする呼出しを制限することが必要な場合もあります。アプリケーションが複数のトランザクションのEJBへの同時アクセスを許可しない場合(たとえばBeanがExclusive同時実行性を使用している場合)、各トランザクションの開始時にデータをロードする必要はありません。他のクライアントやシステムがEJBの基底データを更新しないとすると、キャッシュされたEJBのデータは常に最新の状態であり、ejbLoad()を呼び出すことは余計なオーバーヘッドにつながります。そのような場合は、ejbLoad()の呼出し回数を安全に減らすことができます(「cache-between-transactionsによるデータベース読込みの制限」を参照)。
あるいは、トランザクションの中間結果を利用するために、トランザクションのコミット前に呼び出してejbStore()の標準動作から逸脱することが必要な場合もあるかもしれません。手順については、「トランザクション終了前のデータベースの更新」を参照してください。
EJBの仕様によると、トランザクションによる更新内容は、トランザクションで発行された問合せファインダおよびejbSelectの結果に反映させる必要があります。この要件に従うとパフォーマンスが低下する場合があります。問合せの実行前にキャッシュをフラッシュしたくない場合は、weblogic-cmp-jar.xmlのinclude-updates要素の値をデフォルト値のTrueからFalseに変更できます。
キャッシュのフラッシュを無効にするかどうかは、データが最新であることよりもパフォーマンスを重視するかどうかで判断します。include-updatesをFalseに設定するとパフォーマンスは最高になりますが、現在のトランザクションの更新が問合せで反映されません。include-updatesがTrueの場合、コンテナはトランザクションの変更をすべてデータベースにフラッシュしてから新しい問合せを実行します。
トランザクションが修正されたデータの問合せを再実行しない場合は(一般的なシナリオ)キャッシュのフラッシュを安全にオフにして、最高のパフォーマンスを得ることができます。
アプリケーション・レベルのキャッシング(「組合せキャッシング」とも呼ばれます)では、同じJava EEアプリケーションに属する複数のエンティティBeanが1つの実行時キャッシュを共有できます。各キャッシュを何個のエンティティBeanが参照するかについて制限はありません。
アプリケーション・レベルのキャッシングには以下の利点があります。
エンティティBeanキャッシュの数が減り、その結果としてキャッシュを構成する作業が軽減されます。
フラグメンテーションが減るので、メモリーおよびヒープ・スペースの使用率が向上します。たとえば、特定のEJBホームでアクティビティが急増した場合に、結合したキャッシュで利用可能なすべてのメモリーを利用することができます(キャッシュを使用する他のEJBはページアウトされます)。2つのEJBが異なるキャッシュを使用する場合は、片方のBeanのキャッシュがいっぱいになったときに、コンテナは他のBeanのキャッシュでEJBをページアウトできず、その結果としてメモリーが浪費されます。
管理が簡素化されます。キャッシュの結合により、システム管理者は多くのキャッシュではなく1つのキャッシュのみの調整で済みます。
スケーラビリティが向上します。
ただし、アプリケーション・レベルのキャッシングは、スループットの高いアプリケーションにとっては最適な選択肢ではありません。1つのキャッシュにつき一度に1つの制御スレッドしかないので、スループットが高い場合は、複数のタスクがスレッドの制御を奪い合ってそれがボトルネックになることがあります。
アプリケーション・レベルのキャッシュを構成するには、次の手順に従います。
weblogic-application.xmlファイルがEARファイルのMETA-INFディレクトリ内にあるか確めます。
weblogic-application.xmlのentity-cache要素でアプリケーション・レベルのキャッシュを定義します。この要素とその子要素の定義については、『Oracle WebLogic Serverアプリケーションの開発』のエンタープライズ・アプリケーションのデプロイメント記述子の要素に関する項のentity-cacheに関する項を参照してください。
weblogic-ejb-jar.xmlのentity-descriptor要素のentity-cache-ref要素でアプリケーション・レベルのキャッシュを参照します。
以下の点に注意してください。
entity-cache-nameはweblogic-application.xmlで指定されているアプリケーション・レベルのキャッシュの名前でなければなりません。
Beanで指定するconcurrency-strategyはweblogic-application.xmlのcaching-strategyと一致している必要があります。読取り専用エンティティは、マルチバージョンのアプリケーションレベル・キャッシュのみを使用できます。詳細は、『Oracle WebLogic Serverへのアプリケーションのデプロイ』のエンタープライズ・アプリケーションのデプロイメント記述子の要素に関する項のcaching-strategyに関する項を参照してください。
weblogic-application.xmlデプロイメント記述子については、『Oracle WebLogic Serverへのアプリケーションのデプロイ』のエンタープライズ・アプリケーションのデプロイメント記述子の要素に関する項を参照してください。
すべてのエンティティEJBには、そのホームでエンティティBeanをユニークに識別する主キーが必要です。個々のエンティティBeanインスタンスは、その主キーに対して別のクラスを定義できます(複数のエンティティBeanが必要に応じて同じ主キー・クラスを使用できます)。
2つのエンティティBeanインスタンスのホームと主キーが共通する場合、両者は同一のものと見なされます。クライアントはエンティティBeanインスタンスのリモート・インタフェースへの参照に対してgetPrimaryKey()メソッドを呼び出して、そのホーム内でのインスタンスのIDを調べることができます。
参照と関連付けられたインスタンスIDは、参照が有効な間は変化しません。したがってgetPrimaryKey()メソッドは、同じエンティティ・オブジェクトの参照に対して呼び出されたときは常に同じ値を返します。エンティティ・オブジェクトの主キーを知っているクライアントは、Beanのホーム・インタフェースのfindByPrimaryKey(key)メソッドを呼び出すことによって、エンティティ・オブジェクトへの参照を取得することができます。
主キーは、1つまたは複数のフィールドにマップできます。
主キーを1つのCMPフィールドにマップする
エンティティBeanクラスでは、主キーを1つのCMPフィールドにマップできます。CMPフィールドは、ejb-jar.xmlとweblogic-cmp-jar.xmlの両方で指定する必要があります。両方の記述子ファイルで、CMPフィールドはcmp-field要素で指定します。単純主キーの場合は、ejb-jar.xmlのprimkey-field要素でも主キーを指定します。さらに、ejb-jar.xmlのprim-key-class要素で主キー・フィールドのクラスを指定します。
1つまたは複数のCMPフィールドを主キー・クラスにラップする
1つまたは複数のフィールドに対応する独自の主キー・クラスを定義することができます。主キー・クラスはpublicでなければならず、パラメータを付けないpublicコンストラクタを持たなければなりません。ejb-jar.xmlのprim-key-class要素で主キー・クラスの名前を指定します。主キー・クラスのすべてのフィールドはpublicでなければならず、ejb-jar.xmlおよびweblogic-ejb-jar.xmlの対応するcmp-fieldと同じで名前を持つ必要があります。複数のCMPフィールドに対応する複合主キーの場合は、ejb-jar.xmlでprimkey-fieldを指定しません。
無名主キー・クラス
EJBが無名主キー・クラスを使用する場合、EJBをサブクラス化しjava.lang.Integer型のcmp-fieldをそのサブクラスに追加する必要があります。そのフィールドの自動主キー生成を有効にし、コンテナがフィールドの値を自動的に埋め、そのフィールドをweblogic-cmp-jar.xmlデプロイメント記述子のデータベース列にマップできるようにします。
最終的に、ejb-jar.xmlファイルを更新して元のEJBクラスではなくEJBサブクラスを指定するようにし、そのBeanをWebLogic Serverにデプロイします。
|
注意: 元のEJBを無名主キー・クラスとともに使用した場合、デプロイメント時にWebLogic Serverから次のエラー・メッセージが表示されます。
|
WebLogic Serverで主キーを使用するときには以下の提言に従ってください。
ejbCreateを使用して新しい主キー・クラスを作成しないでください。その代わりに、「主キーの自動生成」の説明に従ってコンテナ内部で主キー・クラスを作成できるようにしてください。
それ独自の主キー値を管理するアプリケーションにおいて、StringまたはIntegerなどの原子的な値1つで構成された単純主キーの場合は、その主キー・クラスをコンテナ管理によるフィールドにします。ejbCreateメソッド内でsetXXXメソッドを使用して、主キーのcmp-fieldの値を設定します。
BigDecimal型のcmp-fieldは、CMP Beanの主キー・フィールドとして使用しないでください。boolean BigDecimal.equals (object x)メソッドでは、値とスケールが同じ場合に限り2つのBigDecimalが等しいと判断されます。なぜなら、Java言語とさまざまなデータベースでは精度に違いがあるからです。たとえば、このメソッドでは7.1と7.10は等しいとは判断されません。したがって、このメソッドを使用すると、ほとんどの場合でFalseが返されるか、CMP Beanでエラーが発生します。
BigDecimalを主キーとして使用する必要がある場合は、次の操作を行ってください。
主キー・クラスを実装します。
この主キー・クラスで、boolean equal (Object x)メソッドを実装します。
equalメソッドで、boolean BigDecimal.compareTo(BigDecimal val)を使用します。
データベース列をcmp-fieldおよびcmr-fieldに同時にマップし、cmp-fieldが主キー・フィールドである場合は、ejbCreate()メソッドが呼び出されたときにcmp-fieldのsetXXXメソッドを使用して値を設定します。その場合、cmr-fieldは自動的に初期化され、cmr-fieldのsetXXXメソッドは使用できません。逆に、cmp-fieldが主キー・フィールドでない場合には、cmp-fieldが読取り専用です。列はcmr-fieldを使用して更新され、cmp-fieldは外部キーの読出し専用ビューを提供します。
WebLogic Serverは、CMPエンティティBeanでの自動主キー生成機能をサポートしています。この機能は、単純(非複合)主キーでのみサポートされています。
WebLogic Serverは、自動主キー生成の2通りの手法をサポートしています。
ネイティブのデータベース主キー生成 - データベースが主キーを生成します。この機能を有効にするには、weblogic-cmp-jar.xmlの<automatic-key-generation>要素でデータベースとジェネレータ名を指定します。コンテナは、構成された値に基づいてデータベースから主キーを取得するコードを生成します。この機能は、OracleおよびMicrosoft SQL Serverデータベースのみでサポートされています。「主キー・フィールドの型の宣言」の手順も参照してください。
SEQUENCE表から生成される主キー
どちらの方法を使用する場合でも、「主キー・フィールドの型の宣言」の手順を参照してください。
Oracleデータベース用の主キー生成サポートでは、OracleデータベースのSEQUENCEエンティティを使用してユニークな主キーを生成します。OracleデータベースのSEQUENCEは、新しい数値が必要な場合に呼び出されます。自動キー生成は、weblogic-cmp-jar.xmlのautomatic-key-generation要素で指定します。generator-nam要素で、OracleデータベースのSEQUENCEの名前を指定します。OracleデータベースのSEQUENCEがSEQUENCE INCREMENTで作成された場合は、key-cache-sizeを指定します。key-cache-sizeの値は、OracleデータベースのSEQUENCE INCREMENTの値と同じでなければなりません。2つの値が違う場合は、キーが重複することがあります。
主キーの生成でOracleデータベースのSEQUENCEオブジェクトを使用する場合は、以下の点に注意してください。
Oracleでは、generator-typeをUSER_DESIGNATED_TABLEに設定しません。そのように設定するとTX ISOLATION LEVELがSERIALIZABLEに設定され、次の例外が生じる場合があります。
javax.ejb.EJBException: nested exception is: java.sql.SQLException: Automatic Key Generation Error: attempted to UPDATE or QUERY NAMED SEQUENCE TABLE NamedSequenceTable, but encountered SQLException java.sql.SQLException: ORA-08177: can't serialize access for this transaction.
代わりに、OracleデータベースではAutoKeyオプションを使用します。
このリリースのWebLogic Serverでは、SEQUENCEスキーマ・オブジェクトに対応するOracleデータベースの同様の機能をサポートしていません。SEQUENCEと同様の機能を使用するアプリケーションをWebLogic Server 8.1より前のリリースからこのリリースに移行すると、以下のエラーが生じます。
[EJB:011066]During EJB deployment, error(s) were encountered while setting up The ORACLE SEQUENCE named 'XXX' with INCREMENT value '1' [EJB:011064]The ORACLE SEQUENCE named 'XXX' with INCREMENT '1' was not found in the database'
Microsoft SQL Serverデータベース用の主キー生成サポートでは、SQL ServerのIDENTITY列が使用されます。Beanが作成され、新しい行がデータベース表に挿入されると、SQL Serverは、IDENTITY列として指定された列に、次の主キー値を自動的に挿入します。
|
注意:
|
表でIDENTITY列が作成されたら、次のようにweblogic-cmp-jar.xmlで自動キー生成を指定してください。
<automatic-key-generation>
<generator-type>SQLServer</generator-type>
</automatic-key-generation>
シーケンス表は、データベースに依存しない主キーを生成する手段です。シーケンス表は、Beanインスタンスの作成時にその主キー値として使用される、一定の割合で増加する整数のシーケンス値を保持します。
現在の主キー値を保持するSEQUENCEという名前の表を作成します。この表は、次の文で定義するように、1行1列で構成されます。
CREATE table_name (SEQUENCE int) INSERT into table_name VALUES (0)
この機能を使用するには、基底のデータベースがトランザクションのアイソレーション・レベルSerializableをサポートしていなければなりません。Serializable値は、このトランザクションを同時に複数回実行すると、トランザクションを順番に複数回実行するのと同じ結果になることを示します。これは、複数のサーバー・インスタンスがシーケンス表に同時にアクセスするWebLogic Serverクラスタで重要です。データベースがサポートするアイソレーション・レベルを確認するには、そのデータベースのドキュメントを参照してください。
自動キー生成は、weblogic-cmp-jar.xmlファイルで次のように指定します。「主キー・フィールドの型の宣言」の手順も参照してください。
<automatic-key-generation>
<generator-type>NamedSequenceTable</generator-type>
MY_SEQUENCE_TABLE_NAME</generator-name>
<key-cache-size>100</key-cache-size>
</automatic-key-generation>
generator-name要素で、シーケンス表の名前を指定します。
キー・キャッシュのサイズ(1回のDBMS呼出しでコンテナが取得するキーの数)は、key-cache-size要素で指定します。key-cache-sizeは、1より大きく設定することをお薦めします。この設定により、次のキー値を取得するためのデータベースの呼出し回数を減らすことができます。
NAMED SEQUENCE表はBeanのタイプごとに定義することをお薦めします。異なるタイプのBeanがNAMED SEQUENCE表を共有しないようにしてください。こうすることで、キー表の競合の発生を防ぎます。
ネイティブのDBMS主キー生成と、命名済シーケンス表を使用したキー生成の両方について、関連付けられたエンティティBeanの抽象getメソッドおよびsetメソッドで、主キー・フィールドの型を以下のいずれかとして宣言します。
java.lang.Integer
java.lang.Long
weblogic-cmp-jar.xmlでは、シーケンスの主キー値がデータベースから一度にいくつ取得されるのかを指定するkey-cache-size要素を設定します。たとえばkey_cache_sizeを10に設定すると、Beanが10作成されるたびに一度データベース・アクセスが実行されてシーケンスが更新されます。key_cache_sizeのデフォルト値は1です。データベース・アクセスを最小限に抑えてパフォーマンスを向上させるために、key_cache_sizeには1より大きい値を設定することを推奨しています。
WebLogic Serverは、OracleデータベースのSEQUENCE (呼び出されるたびにユニークな整数を生成する番号ジェネレータ)を自動的に作成できます。
OracleデータベースのSEQUENCEは、指定された「インクリメント値」を使用できます。インクリメント値とは、生成ごとに整数が大きくなる増加量のことです。たとえば、SEQUENCEで整数24が生成され、インクリメント値が10の場合、SEQUENCE で生成される次の整数は34になります。
このリリースのWebLogic Serverでは、デフォルトによって、EJBコンテナは文字列値CMPフィールドがデータベースから取得されたときにその末尾のスペースを削除します。すべての文字列値CMPフィールドのセット・メソッドでも、末尾のスペースが削除されます。
主キー・フィールド内のスペースを削除しない場合、比較演算子が正常に機能せず、移植できない動作を引き起こす場合があります。自動文字列削除の利点は、データベースから取得された文字列が、データベースに挿入された文字列と同じになることです。次に例を示します。
主キー・フィールドがデータベース内のchar(10)データ型にマップされています。
データベース列に「smith」という値を挿入します。
"smith"は5文字であり、char型は固定長の10文字であるため、データベースは5個のスペースを末尾に追加して値を埋めます。この結果、データベースには"smith "という値が挿入されます。
SELECT文を使用して、データベースから"smith"を検索します。データベースによって追加された文字列である"smith "が取得されます。
取得した"smith "と元の"smith"の比較演算は、取得した値の末尾のスペースを事前に削除しない限り失敗します。このリリースのWebLogic Serverでは、末尾のスペースは自動的に削除されるため、比較演算が失敗することはありません。
このリリースでは、デフォルトによって自動文字列削除が有効になっています。DDConverterを使用して旧リリースのWebLogic Serverのデプロイメント記述子を変換する場合、DDConverterは作成する新しいデプロイメント記述子で文字列削除を自動的に無効にします。
このリリースのWebLogic Serverで新しく作成するデプロイメント記述子で文字列削除を無効にする場合、weblogic-cmp-jar.xmlのdisable-string-trimmingをTrueに設定します。disable-string-trimming要素の詳細については、「disable-string-trimming」を参照してください。
この節では、エンティティEJBをデータベース表にマップし、データベース・アクセスの動作を制御する方法を示します。
CMP Beanは、1つまたは複数のデータベース表にマップできます。1つのCMP Beanを複数の表にマップする場合、各表には、1つの特定のBeanインスタンスに対応する1行が含まれます。このため、Beanがマップされる各表にはいつでも同じ数の行が含まれ、同種の主キー値が同じように格納されます。したがって、各表には同数の主キー列が含まれ、別々の表の対応している主キー列どうしは名前は違うとしても同じタイプでなければなりません。同じBeanにマップされる複数の表の主キー間に、参照一貫性制約を課してはなりません。参照一貫性制約がある場合は、Beanインスタンスを削除すると実行時エラーが発生します。
Beanのcmp-fieldを表の列にマップするには、weblogic-cmp-jar.xmlのtable-map要素を使用します。その際、Beanがマップされるデータベース表ごとに1つのtable-map要素を指定します。各table-map要素は、表の主キー列をBeanの主キー・フィールドにマップします。主キー以外のフィールドは、1つの表にマップされるだけの場合もあります。
例6-1と例6-2は、1つの表にマップされるBeanと複数の表にマップされるBeanのtable-map要素を示しています。
例6-1 CMPエンティティの1つのデータベース表へのマッピング
<table-map>
<table-name>TableName</table-name>
<field-map>
<cmp-field>name</cmp-field>
<dbms-column>name_in_tablename</dbms-column>
</field-map>
<field-map>
<cmp-field>street_address</cmp-field>
<dbms-column>street_address_in_tablename
</dbms_column>
</field-map>
<field-map>
<cmp-field>phone</cmp-field>
<dbms-column>phone_in_tablename</dbms-column>
</field-map>
例6-2 CMPエンティティの2つのDBMS表へのマッピング
<table-map>
<table-name>TableName_1</table-name>
<field-map>
<!--Note 'name'is the primary key field of this EJB -->
<cmp-field>name</cmp-field>
<dbms-column>name_in_tablename_1</dbms-column>
</field-map>
<field-map>
<cmp-field>street_address</cmp-field>
<dbms-column>street_address_in_tablename_1</dbms-column>
</field-map>
</table-map>
<table-map>
<table-name>TableName_2</table-name>
<field-map>
<!--Note 'name'is the primary key field of this EJB -->
<cmp-field>name</cmp-field>
<dbms-column>name_in_tablename_2</dbms-column>
</field-map>
<field-map>
<cmp-field>phone</cmp-field>
<dbms-column>phone_in_tablename_2</dbms-column>
</field-map>
</table-map>
WebLogic ServerのEJBコンテナは、反復的な開発を容易にするために、エンティティBeanが変更されたときに自動的に基底の表スキーマを変更するように構成できます。そのように構成すると、表はオブジェクトの関係の最新のマッピングを常に反映するようになります。
|
注意: この機能は、サーバー・インスタンスがプロダクション・モードで実行されている場合は無効です。プロダクション環境では、より正確な表スキーマ定義を使用することが必要な場合があるからです。確実にコンテナによって作成された表だけが変更されるように、コンテナで作成された表には、 |
表作成文の構文(DDL)はデータベースによって異なるので、表の作成はフル・サポートされていないデータベースでは失敗する場合があります。その場合、表は手作業で作成します。
表6-2 <create-default-dbms-tables>を使用した自動表作成動作の制御
| <create-default-dbms-tables>の設定値 | 得られる動作 |
|---|---|
|
|
基底の表スキーマが変更されてもEJBコンテナはアクションを行いません。これがデフォルト値です。 |
|
|
|
|
|
注意: 列タイプとcmpフィールド・タイプの間に互換性があることを確認する必要があります。EJBコンテナは、列タイプとcmpフィールド・タイプの間に互換性があることを確認しません。 |
|
|
|
|
|
注意: 新しい列が主キーとして指定されているか、値がnullの列が新しい主キー列として指定されている場合には、 |
|
注意: シーケンス表、結合表、およびOracleデータベースのSEQUENCEがサポートされています。 |
weblogic-cmp-jar.xmlのcreate-default-dbms-table要素を使用してこの機能を有効化します。この機能の動作は、次の表で説明するように、要素の値に応じて変わります。この表に示すEJBコンテナのアクションは、デプロイ中に発生します。
CMP Beanを作成するときに発生する場合のあるタイミングの問題のため、WebLogic ServerではBeanの作成プロセスのどの時点でBeanがデータベースに挿入されるのかを指定することができます。
cmr-fieldは、Beanの主キー値(ejbPostCreateが呼び出されて設定される)がアクセス可能になるまで設定できません。したがって、cmr-fieldはejbPostCreateが呼び出されるまで設定できません。この要因が他の条件と重なると、以下の問題が生じることがあります。
問題1: 非nullの外部キーの制約
データベースの行がejbCreateの後(つまり、ejbPostCreateの前)に挿入された場合、外部キーはnull値になります。その理由は、外部キー列がcmr-fieldの設定時に設定されるからです。
解決策: weblogic-cmp-jar.xmlのdelay-insert-untilをejbCreateに設定し(この設定で、挿入はejbCreateの直後に行われます)、ejbPostCreateの過程で関係を設定します。
問題2 : ejbPostCreateの過程でのBeanの作成
関連するBeanが作成されるときに、そのBeanのデータベースの挿入が、作成の呼出しが終了する前に行われます。関連するBeanのデータベース行に、現在のBeanを表す外部キーが含まれており、その外部キーで参照一貫性制約が定義されている場合、挿入は現在のBeanのデータベース行がまだ挿入されていない場合は失敗します。
解決策: delay-insert-untilをejbCreateに設定し、現在のBeanの行がejbPostCreateの間存在するようにします。
|
注意: 1対1の関係では、親Beanの主キーが子BeanのCMRフィールドに埋め込まれている場合、EJBコンテナがBeanを作成するときに、パフォーマンス上の理由からその親Beanに子があるかどうかが確認されません。 |
問題3: 問題1と問題2の両方がある
解決策: ejbPostCreateの間に関連するBeanを作成しないようにします。現在のBeanを作成し、その作成が終了した後に、関連するBeanを作成して関係を設定します。
これが、アプリケーションで常に行われるようにすることをお薦めします。アプリケーションでは、別のBeanの作成時に関連するBeanを作成してはなりません。
weblogic-cmp-jar.xmlのdelay-database-insert-until要素を使用すると、EJBCreateメソッドまたはejbPostCreateメソッドが終了するまでデータベースの挿入を遅らせることができます。トランザクションの最後に更新を一括で順序付けして実行するには、weblogic-cmp-jar.xmlでenable-batch-operationsとorder-database-operationsの両方を「True」に設定します。
関連するBeanを更新するトランザクションでデータベースの更新を遅延させる場合は、weblogic-cmp-jar.xmlのweblogic-rdbms-relationでBean間の関係を定義する必要があります。そのように定義しないと、EJBコンテナが更新を実行しようとしたときに、データベースの制約エラーが発生する場合があります。
「ejbLoad()とejbStore()の動作について」で説明されているように、デフォルトでは、WebLogic ServerはエンティティBeanでトランザクションが開始されるたびにejbLoad()を呼び出します。
クライアントが最初にBeanを参照するとき、またはトランザクションがロールバックされたときにのみejbLoad()を呼び出すようにWebLogic Serverを構成できます。この動作は、長期キャッシングと呼ばれます。長期キャッシングを有効化するには、weblogic-ejb-jar.xmlのcache-between-transactions要素をtrueに設定します。
長期キャッシングは、Beanのconcurrency-strategyがExclusive、ReadOnly、またはOptimisticの場合のみ許可されます。長期キャッシングが構成されている場合の動作は以下のとおりです。
ReadOnly Beanの場合、WebLogic Serverはcache-between-transactionsの値を無視します。WebLogic Serverは、cache-between-transactionsの値に関係なく常に読取り専用データの長期キャッシングを実行します。
Exclusive Beanの場合、EJBコンテナは基底データへの排他的な更新アクセスが可能である必要があります。データが、EJBコンテナ外の別のアプリケーションで更新されることはあってはなりません。
|
注意:
|
Optimistic Beanの場合、EJBコンテナはクライアントが最初にBeanを参照した後に各トランザクションでキャッシュされたデータを再利用しますが、各トランザクションの最後にオプティミスティックな衝突をチェックすることで更新がトランザクションとして一貫性を持つようにします。
|
注意: クラスタでは、オプティミスティック同時実行性のBeanが更新されると、オプティミスティックな衝突を防止するために他のクラスタ・メンバーに通知がブロードキャストされます。 |
表6-3は、エンティティBeanのタイプおよび同時実行性ストラテジ別のcache-between-transactions 要素の有効値を示しています。
「ejbLoad()とejbStore()の動作について」で説明されているように、デフォルトでは、WebLogic Serverはトランザクションのコミット時にのみejbStore()を呼び出します。
未コミット・トランザクションの中間結果を他のデータベース・ユーザーが利用できるようにするには、weblogic-ejb-jar.xmlのpersistence要素のdelay-updates-until-end-of-txをFalseに設定します。この設定により、WebLogic Serverは各メソッド呼出しの後にejbStore()を呼び出すようになります。
|
注意:
|
動的問合せを使用すると、各自のアプリケーション・コードでEJB-QLまたはSQL問合せをプログラム的に作成および実行できるようになります。
動的問合せの使用には、次のような利点があります。
EJBを更新してデプロイせずに、新しい問合せを作成して実行する機能。
EJBデプロイメント記述子ファイルのサイズを縮小する機能。ファインダ問合せがデプロイメント記述子内で静的に定義される代わりに、動的に作成されるようになるためです。
動的問合せを有効化するには、次の手順に従います。
EJBのweblogic-ejb-jar.xmlのenable-dynamic-queries要素をTrueに設定します。
<enable-dynamic-queries>True</enable-dynamic-queries>
ejb-jar.xmlデプロイメント記述子ファイルのmethod-permission 要素を指定することによって、標準メソッド権限を設定し、動的問合せへのアクセスを制御します。
weblogic.ejb.QueryHomeインタフェースのcreateQuery()メソッドのmethod-permissionを設定することによって、動的問合せを実行するweblogic.ejb.Queryオブジェクトへのアクセスを制御します。
createQuery()メソッドのmethod-permissionを指定した場合、method-permissionの設定がQueryクラスの実行と検索メソッドに適用されます。
次のサンプル・コードでは、動的問合せをどのように実行するかを示します。
InitialContext ic=new InitialContext();
FooHome fh=(FooHome)ic.lookup("fooHome");
QueryHome qh=(QueryHome)fh;
String ejbql="SELECT OBJECT(e)FROM EmployeeBean e WHERE e.name='rob'"
Query query=qh.createQuery();
query.setMaxElements(10)
Collection results=query.find(ejbql);
WebLogic Serverは、OracleおよびDB2データベースのBinary Large Object (BLOB)およびCharacter Large Object (CLOB) DBMS列をCMPエンティティBeanでサポートしています。
WebLogic Serverは、バイト配列またはシリアライズ可能な型を持つcmp-fieldにBLOBをマップします。現時点では、char配列をCLOB列にマップすることはできません。
BLOB/CLOBサポートを有効にするには次の手順に従います。
Beanクラスで変数を宣言します。
weblogic-cmp-jar.xmlファイルでdbms-default-valueおよびdbms-column-typeデプロイメント記述子を宣言してXMLを編集します。
OracleまたはDB2データベースにBLOBまたはCLOBを作成します。
次のXMLコードは、weblogic-cmp-jar-xmlファイルのdbms-column-type要素を使用してBLOBオブジェクトを指定する方法を示しています。
<field-map>
<cmp-field>photo</cmp-field>
<dbms-column>PICTURE</dbms-column>
<dbms-column-type>Blob</dbms-column-type>
<dbms-default-value>DB2</dbms-default-value>
</field-map>
このリリースのWebLogic Serverでは、Blobにマップされるbyte[]型のcmp-fieldはデフォルトによってシリアライズされません。EJBコンテナはbyte[]型を直接保持し、シリアライズしません。
WebLogic ServerがOracleデータベース内のBlobにマップされたbyte[]型のcmp-fieldをシリアライズするようにするには、WebLogic Server 8.1 SP02で導入されたserialize-byte-array-to-oracle-blob互換性フラグをTrueに設定します。
次のXMLコードは、weblogic-cmp-jar-xmlファイルのdbms-column要素を使用してCLOBオブジェクトを指定する方法を示しています。
<field-map>
<cmp-field>description</cmp-field>
<dbms-column>product_description</dbms-column>
<dbms_column-type>Clob</dbms-column-type>
<dbms-default-value>Oracle</dbms-default-value>
</field-map>
Oracle 9iドライバと10gドライバでは、CLOB列をデータベースに正常に挿入するための要件が異なっています。Oracle 9iドライバでは、CLOB値を挿入する前に、データベース行をロックする必要があります。したがって、Oracle 9iの場合、WebLogic Serverは以下の手順でCLOB列値を含む行を表に挿入しています。
CLOB列以外のすべての値を含む行を表に挿入します。
手順1で作成された行に対してSELECT FOR UPDATE文を発行します。
その行にCLOB値を挿入します。
Oracle 9iでCLOB値を含む行を正常に挿入するにはこのような手順が必要ですが、Oracle 10gでこの手順を行うと、パフォーマンスに不要な影響を与えます。Oracle 10gドライバではCLOBの処理方法が改良されており、CLOB列値を挿入する前に行をロックする必要はありません。Oracle 10gの場合、WebLogic Serverは単一のINSERT文を使用して、CLOB列値を含む行を表に挿入します。その結果、CMP EJBのパフォーマンスは向上します。
このようなOracle 10gに関するWebLogic Serverの最適化を利用するために、追加の構成は必要ありません。データベースとしてOracleを指定すれば、WebLogic ServerはOracleのバージョンがOracle 9iかOracle 10gかを確認します。WebLogic ServerがデータベースをOracle 10gと識別した場合、CLOB値を含む行は単一のINSERT文で表に挿入されます。WebLogic ServerがデータベースをOracle 9iと識別した場合、CLOB値を含む行は前述の3つの手順で表に挿入されます。
詳細は、「Handling CLOBs - Made easy with Oracle JDBC 10g」(http://www.oracle.com/technetwork/java/jms/index.html#DUPS_OK_ACKNOWLEDGE)を参照してください。
フィールド・グループは、Beanのコンテナ管理による永続性(CMP)フィールドとコンテナ管理による関係(CMR)フィールドのサブセットを表します。パフォーマンスを向上させるために、Bean内の関連フィールドを、障害のあったグループにまとめて1つのユニットとしてメモリー内に入れることができます。
グループを問合せまたは関係に関連付けることができます。それによって、問合せを実行するか、または関係に従った結果としてBeanがロードされたときに、グループ内の指定フィールドのみがロードされます。
指定したグループを持たない問合せと関係に対して、「default」という特殊なグループを使用します。デフォルトでは、defaultグループには、BeanのすべてのCMPフィールドと、Bean表に外部キーを追加するすべてのCMRフィールドが格納されます。
フィールドは複数のグループに関連付けられている場合があります。この場合、フィールドに対してgetXXX()メソッドを実行すると、そのフィールドを含む最初のグループで障害が発生します。
フィールド・グループは、例6-3のようにweblogic-cmp-jar.xmlファイルのfield-group要素で指定します。
同じコンテナ管理による永続性(CMP)エンティティBeanの複数のインスタンスは、多くの場合単一のトランザクションで変更されます。EJBコンテナがCMPエンティティBeanのインスタンスごとにSQLを発行する場合、更新はパフォーマンスのボトルネックになります。
EJBバッチ処理機能は、1まとまりのSQL文でデータベース表内の複数エントリを更新することにより、この問題を解決します。これにより、CMP Beanの複数のデータベース挿入、削除、または更新を一度のデータベース・アクセスで実行することでパフォーマンスが大幅に向上します。
バッチ処理によるデータベース挿入、更新、または削除を許可するには、weblogic-cmp-jar.xmlファイルのenable-batch-operations要素をTrueに設定します。
データベースの処理を順序付けすると、データベースの依存関係を考慮し、それに応じて挿入、更新、および削除を順序付けすることで制約エラーが起こらなくなります。
データベースの順序付けを有効化すると、EJBコンテナが次の2つの処理を行うようになります。
データベースのすべての処理(挿入、更新、および削除)をコミット時間まで遅延させる
コミット時間になったらデータベース処理を順序付けする
たとえば、販売員Aと関連する顧客Aを想定します。販売員Aが削除され、顧客Aが販売員Bに割り当てられる場合、コンテナは次のように処理を順序付けします。
販売員Bを参照するように顧客Aを更新します。
販売員Aを削除します。
これで、顧客Aは存在しない販売員を参照しなくなり、データベースの参照整合性エラーが発生しなくなります。
EJBコンテナが関連するBeanのデータベース処理を適切に順序付けするには、weblogic-cmp-jar.xmlのweblogic-rdbms-relationでBean間の関係を定義する必要があります。そのように定義しないと、EJBコンテナが更新を実行しようとしたときに、データベースの制約エラーが発生する場合があります。
バッチ処理を使用する場合、トランザクションの開始からコミットまでの間にバッチ処理だけが挿入、更新または削除に適用されるように、トランザクションの境界を設定しなければなりません。
バッチ処理は、addBatch()とexecuteBatch()メソッドをサポートしているドライバのみに機能します。サポートされていないドライバを検出すると、EJBコンテナはバッチ処理がサポートされていないことを報告し、バッチ処理を無効化します。
バッチ処理の使用には、いくつかの制限があります。
generator-typeがsybaseまたはsqlServerに設定されていると、バッチ処理で主キーの自動生成機能を使用できません。これらのタイプのいずれかで自動主キー生成を有効化していた場合、WebLogic Serverは自動的にバッチ処理を無効化し、警告を発行します。
1回のバッチ処理で作成するエントリの総数が、weblogic-ejb-jar.xmlファイルで指定したmax-beans-in-cacheの設定値を超えることはできません。
weblogic-cmp-jar.xmlのdbms-column-type要素でBlobかClobを設定した場合、バッチ処理は自動的に無効になります。BlobまたはClob列がデータベース表に含まれている状況では、時間をあまり短縮できないからです。この場合、デフォルトではWebLogic ServerはBeanごとに挿入を実行します。
読取り専用エンティティEJBを問合せレベルでキャッシュできます。読取り専用エンティティEJBを問合せレベルでキャッシュすると、パフォーマンスが向上します。これは、ファインダがキャッシュ内のEJBにアクセスできるようになり、データベースへのアクセスを回避できるからです。詳細については、「enable-query-caching」を参照してください。
このリリースのWebLogic Serverでは、コンテナ管理による永続性(CMP)を使用するエンティティBeanでEJB-QL、標準のSQL、またはデータベース固有のSQLを使用できます。ほとんどの問合せではEJB-QL (WebLogic拡張ありまたはなし)を使用し、SQLは必要な場合にのみ(たとえば、ベンダー固有のSQLを使用しないとアクセスできないベンダー固有機能を使用する場合に)使用することをお薦めします。
SQLは、複数の関連オブジェクトをキャッシュする問合せでファインダおよび選択メソッドを実装するために使用したり、ストアド・プロシージャと一緒に使用したりできます。
このリリースのWebLogic Serverの問合せでEJB-QLを使用する場合、weblogic-cmp-jar.xmlのマッピング情報を変更する必要はありません。9.0より前のリリースのWebLogic Serverでの操作と同じように、各CMPおよびCMRフィールドをデータベース列にマップするだけです。詳細は、「データベース操作に向けたエンティティEJBの構成」および「コンテナ管理による関係(CMR)の使用」を参照してください。問合せでSQLを使用するには、sql-shape要素を使用してSQL結果の形式を記述する必要があります。SQLの形式は、主に返されるSQL表と列で構成されます。EJBコンテナは、SQLの形式とCMPおよびCMPフィールド・マッピングを使用して問合せからオブジェクトを返します。詳細は、次を参照してください:
コンテナ管理による関係(CMR)は2つのエンティティEJB間で定義する関係であり、データベースの表間の関係と似ています。同じ処理タスクに関わる2つのEJB間でCMRを定義した場合、アプリケーションは以下の機能の恩恵を受けることができます。
関連するBeanを一緒にキャッシュでき、処理タスクを完遂するために必要な問合せの数を減らすことができる
バッチ処理されるデータベース操作をトランザクションの最後に正しく順序付けし、データ一貫性の問題を避けることができる
カスケード削除機能を使用して、関連するBeanを自動的に削除できる
以降の節では、WebLogic Server CMRの特徴と制限について説明します。CMRの構成手順については、「コンテナ管理による関係(CMR)の定義」を参照してください。
同じJARにパッケージ化され、データが同じデータベースに格納される2つのWebLogic ServerエンティティBeanの間で関係を定義できます。同じ関係に属するエンティティは、同じデータ・ソースにマップされていなければなりません。WebLogic Serverは、データ・ソースの異なるエンティティBean間の関係をサポートしていません。コンテナ管理による関係に参加する各Beanの抽象スキーマは、同じejb-jar.xmlファイルで定義されなければなりません。
EJB 2.1では、エンティティBeanにローカル・インタフェースがない場合、そのBeanが参加できる唯一のCMRはそれ自体から別のエンティティBeanへの一方向のCMRであるとされています。ただし、WebLogic Serverではリモート・インタフェースのみのエンティティBeanに以下のことを許可しています。
双方向のCMRに参加する
別のエンティティとの一方向CMRのターゲットになる
この機能はEJB 2.1では規定されていないので、リモート・インタフェースしか持たず、双方向の関係に参加するか、一方向の関係のターゲットとなるエンティティBeanは他のアプリケーション・サーバーには移行できない場合があります。
1対1、1対多、多対多のどれであるかに関係なく、CMRは一方向か双方向のいずれかになります。CMRの方向は、関係の片側のBeanがもう片側のBeanからアクセスできるかどうかを決めます。
一方向のCMRは一方通行であり、「従属」Beanは関係のもう一方のBeanを意識しません。カスケード削除などのCMR関連の機能は、従属Beanにのみ適用できます。たとえば、EJB1からEJB2への一方向のCMRでカスケード削除が構成されている場合、EJB1を削除するとEJB2も削除されますが、EJB2を削除してもEJB1は削除されません。
|
注意: カスケード削除の機能には、関係のカーディナリティが影響します。関係が双方向だとしても、カスケード削除は関係の多サイドからはサポートされません。 |
双方向の関係は両側通行であり、関係の各Beanは他方のBeanを意識しています。CMR関連の機能は、両方向でサポートされます。たとえば、EJB1とEJB2の間の双方向CMRでカスケード削除が構成されている場合、CMRのいずれかのBeanを削除するともう片方のBeanも削除されます。
関係に参加しているBeanインスタンスが削除されると、コンテナは自動的にその関係を削除します。たとえば従業員と部署の間の関係があるとして、その従業員が削除されると、コンテナはその従業員と部署の間の関係も削除します。
CMRの定義では、その関係とカーディナリティおよび方向をejb-jar.xmlで指定します。weblogic-cmp-jar.xmlでは、関係のデータベース・マッピング情報を定義し、リレーションシップ・キャッシングを有効にします。手順については、以下を参照してください。
コンテナ管理による関係は、ejb-jar.xmlのejb-relation要素で定義します。例6-4は、2つのエンティティEJB (TeacherEJBとStudentEJB)間の関係のejb-relation要素を示しています。
ejb-relation要素には、関係の各サイドのejb-relationship-roleがあります。role要素は、各Beanの関係に対する見方を指定します。
例6-4 ejb-jar.xmlでの1対多、双方向のCMR
<ejb-relation>
<ejb-relation-name>TeacherEJB-StudentEJB</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>teacher-has-student
</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>TeacherEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>teacher</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>student-has-teacher
</ejb-relationship-role-name>
<multiplicity>Many</multiplicity>
<relationship-role-source>
<ejb-name>StudentEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>student</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
関係の各サイドのカーディナリティは、ejb-relationship-role要素のmultiplicity要素で示します。
例6-5では、関係TeacherEJB-StudentEJBのカーディナリティは1対多です。このカーディナリティは、TeacherEJB側でmultiplicityをoneに、StudentEJB側ではManyに設定することで指定します。
例6-5のCMRのカーディナリティは1対1です。関係の両方のrole要素でmultiplicityがoneに設定されています。
例6-5 ejb-jar.xmlでの1対1、一方向のCMR
<ejb-relation><ejb-relation-name>MentorEJB-StudentEJB</ejb-relation-name><ejb-relationship-role><ejb-relationship-role-name>mentor-has-student</ejb-relationship-role-name><multiplicity>One</multiplicity><relationship-role-source><ejb-name>MentorEJB</ejb-name></relationship-role-source><cmr-field><cmr-field-name>mentorID</cmr-field-name></cmr-field></ejb-relationship-role><ejb-relationship-role><ejb-relationship-role-name>student-has-mentor</ejb-relationship-role-name><multiplicity>One</multiplicity><relationship-role-source><ejb-name>StudentEJB</ejb-name></relationship-role-source></ejb-relationship-role>
関係の片側の<multiplicity>がManyである場合、その<cmr-field>は集合であり、例6-4の関係StudentEJB側のように、<cmr-field-type>をjava.util.Collectionとして指定する必要があります。cmr-fieldが単一値のオブジェクトである場合は、cmr-field-typeを指定する必要はありません。
表6-4は、関係のカーディナリティに基づいて、関係の各Beanのcmr-fieldの内容を示しています。
CMRの方向は、関係の各サイドのejb-relationship-role要素でcmr-fieldを含めるかどうかによって構成します。
双方向CMRでは、関係の両サイドのejb-relationship-role要素にcmr-field 要素があります(図6-1を参照)。
一方向の関係では、関係のrole要素の片方だけにしかcmr-fieldがありません。開始側EJBのejb-relationship-roleにはcmr-fieldがありますが、ターゲットBeanのrole要素にはありません。図6-1では、MentorEJBからStudentEJBへの一方向の関係が指定されています。StudentEJBのejb-relationship-role要素にはcmr-field 要素がありません。
ejb-jar.xmlで定義される各CMRは、weblogic-cmp-jar.xmlのweblogic-rdbms-relation要素でも定義する必要があります。weblogic-rdbms-relationは関係を識別し、relationship-role-map要素を格納します。この要素は、関係の片側または両側で、関係の参加者間のデータベース・レベルの関係をマップします。
weblogic-rdbms-relationのrelation-nameは、ejb-jar.xmlのCMRのejb-relation-nameと同じでなければなりません。
対1の関係と1対多の関係では、関係の片側だけでrelationship-role-mapが定義されます。
1対1の関係の場合、マッピングは片方のBeanの外部キーからもう片方のBeanの主キーです。
図6-1は、MentorEJBとStudentEJB間の1対1の関係のweblogic-rdbms-relation要素です。<ejb-relation>は、図6-1に示してあります。
例6-6 1対1のCMRのweblogic-cmp-jar.xml
<weblogic-rdbms-relation>
<relation-name>MentorEJB-StudentEJB</relation-name>
<weblogic-relationship-role>
<relationship-role-name>
mentor-has-student
</relationship-role-name>
<relationship-role-map>
<column-map>
<foreign-key-column>student</foreign-key-column>
<key-column>StudentID/key-column>
</column-map>
</relationship-role-map>
</weblogic-relationship-role>
1対多の関係の場合、マッピングは常に片方のBeanの外部キーから別のBeanの主キーです。1対多の関係では、外部キーは常に関係の多サイドにあるBeanと関連付けられます。
例6-7は、TeacherEJBとStudentEJB間の1対多の関係のweblogic-rdbms-relation要素です。<ejb-relation>は、例6-4に示してあります。
例6-7 1対多CMRのweblogic-rdbms-relation
<weblogic-rdbms-relation>
<relation-name>TeacherEJB-StudentEJB</relation-name>
<weblogic-relationship-role>
<relationship-role-name>
teacher-has-student
</relationship-role-name>
<relationship-role-map>
<column-map>
<foreign-key-column>student</foreign-key-column>
<key-column>StudentID/key-column>
</column-map>
</relationship-role-map>
</weblogic-relationship-role>
多対多の関係では、関係の各サイドでweblogic-relationship-role要素を指定します。そのマッピングには、結合表が関わります。結合表の各行には、関係に関与するエンティティの主キーに対応する2つの外部キーが格納されます。関係の方向は、関係のデータベース・マッピングを指定する方法に影響しません。
例6-8は、2人の従業員間のfriends関係のweblogic-rdbms-relation要素を示しています。
FRIENDS結合表には、first-friend-idとsecond-friend-idという2つの列があります。各列には、別の従業員の友人である特定の従業員を示す外部キーが格納されます。従業員表の主キー列はidです。例では、従業員Beanが単一表にマップされているものと想定しています。従業員Beanが複数の表にマップされている場合は、主キー列を格納する表をrelation-role-mapで指定する必要があります。例については、「複数の表にマップされるEJBのCMRの指定」を参照してください。
例6-8 多対多CMRのweblogic-rdbms-relation
<weblogic-rdbms-relation>
<relation-name>friends</relation-name>
<table-name>FRIENDS</table-name>
<weblogic-relationship-role>
<relationship-role-name>first-friend
</relationship-role-name>
<relationship-role-map>
<column-map>
<foreign-key-column>first-friend-id</foreign-key-column>
<key-column>id</key-column>
</column-map
</relationship-role-map>
<weblogic-relationship-role>
<weblogic-relationship-role>
<relationship-role-name>second-friend</relationship-role-name>
<relationship-role-map>
<column-map>
<foreign-key-column>second-friend-id</foreign-key-column>
<key-column>id</key-column>
</column-map>
</relationship-role-map>
</weblogic-relationship-role>
</weblogic-rdbms-relation>
関係に参加するCMP Beanは、複数のDBMS表にマップできます。
1対1または1対多の関係の外部キー側のBeanが複数の表にマップされている場合は、外部キー列が含まれる表の名前をforeign-key-table要素で指定する必要があります。
逆に1対1または1対多の関係の主キー側のBeanまたは多対多の関係に参加しているBeanが複数の表にマップされている場合は、主キーが含まれる表の名前をprimary-key-table要素で指定する必要があります。
関係のどちら側のBeanも複数の表にマップされていない場合、foreign-key-table要素とprimary-key-table要素は省略可能です(使用される表が暗黙的であるため)。
例6-9は、1対1の関係の外部キー側のBean (Fk_Bean)が2つの表(Fk_BeanTable_1とFk_BeanTable_2)にマップされているCMRのrelationship-role-mapです。
関係の外部キー列(Fk_column_1とFk_column_2)は、Fk_BeanTable_2に配置されています。主キー側のBean (Pk_Bean)は、主キー列Pk_table_pkColumn_1とPk_table_pkColumn_2を持つ1つの表にマップされています。
外部キー列を持つ表は、<foreign-key-table>要素で指定する必要があります。
例6-9 1対1のCMR、1つのBeanの複数表へのマッピング
<relationship-role-map
<foreign-key-table>Fk_BeanTable_2</foreign-key-table>
<column-map>
<foreign-key-column>Fk_column_1</foreign-key-column>
<key-column>Pk_table_pkColumn_1</key-column>
</column-map>
<column-map>
<foreign-key-column>Fk_column_2</foreign-key-column>
<key-column>Pk_table_pkColumn_2</key-column>
</column-map>
</relationship-role-map>
CMRフィールドは、実装クラスの属性としては格納されません。CMRフィールドは、記述したCMRフィールドのアクセサ・メソッドを使用してBeanの中でアクセスできます。CMRフィールド・アクセサ・メソッドは次のとおりです。
get...()およびset...()で始まる必要があり、get.../set...の後のテキストはejb-jar.xmlで宣言されている関係フィールドの名前と同じでなければならない
各CMRフィールドの実装クラスに存在している必要がある
abstractとして宣言する必要がある
リモート・クライアントがCMRフィールドのアクセサ・メソッドを使用できるようにするには、ゲッターおよびセッター・メソッドのシグネチャをリモート・インタフェースに配置します。ただし、Collectionデータ型のCMRフィールドはリモート・インタフェースでエクスポーズできません。Collectionデータ型のCMRフィールドは、ローカル・メソッドでのみアクセスできます。
カスケード削除が実行される場合、別のbeanインスタンスとの関係に参加しているbeanインスタンスを削除すると、コンテナは従属するすべてのbeanインスタンスも自動的に削除します。この機能では、データの整合性を効率的に維持できます。
たとえば、Employee BeanがEmployee_Projects Beanとの間で1対多の関係にある場合、Employee Beanのインスタンスを削除するとEmployee_Projects Beanのインスタンスも削除されます。
指定できるカスケード削除は1対1関係と1対多関係についてであり、多対多関係については指定できません。
WebLogic Serverは、2通りのカスケード削除をサポートしています。
Java EEカスケード削除 - この方法では、基底のデータベースでカスケード削除がサポートされている必要がありません。構成するには、次の例のようにejb-jar.xmlでcascade-delete要素を使用します。
<ejb-relation>
<ejb-relation-name>Customer-Account</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>Account-Has-Customer
</ejb-relationship-role-name>
<multiplicity>one</multiplicity>
<cascade-delete/>
</ejb-relationship-role>
</ejb-relation>
|
注意:
|
データベース・レベルのカスケード削除(Oracleのみ) - この方法では、アプリケーションはデータベースに組み込まれているカスケード削除のサポートを利用でき、パフォーマンスの向上を実現できる場合があります。db-cascade-deleteが有効になっている場合は、基底のデータベースをカスケード削除対応に設定する必要があります。Oracle WebLogic Serverでデータベースのカスケード削除を設定する手順と例については、「db-cascade-delete」を参照してください。
大規模なトランザクション環境では、カスケード削除を実行するトランザクションが、カスケード削除を実行しないトランザクションと同じBeanにアクセスする必要がある場合に、排他的同時実行性を使用するトランザクションでデッドロックが発生する可能性があります。そのようなデッドロックを回避する方法については、「排他的同時実行性およびカスケード削除を使用するデッドロックの回避」を参照してください。
リレーションシップ・キャッシング(「プリフェッチ」または「期待されるリレーションシップ・キャッシング」とも呼ばれる)では、関係する複数Beanをキャッシュにロードし、それらに結合問合せを発行して問合せの発行回数を削減することによって、エンティティBeanのパフォーマンスが高められます。Beanの集合が同じ処理単位の中でアクセスされる場合、アプリケーションはそれらを同時にキャッシュにロードする必要があります。
アプリケーションに、次のような関係を持つエンティティBeanが含まれているとします。
customerBean has a one-to-many relationship with accountBean accountBean has a one-to-one relationship with addressBean customerBean has a one-to-one relationship with phoneBean
accountBeanおよびaddressBeanのEJBコード(1対1の関係を持つ)を検討します。
Account acct = acctHome.findByPrimaryKey("103243");
Address addr = acct.getAddress();
リレーションシップ・キャッシングが行われなければ、コードの1行目でaccountBeanをロードするSQL問合せが発行され、2行目でaddressBeanをロードする別のSQL問合せが発行されます。これにより、データベースには2つの問合せが生じます。
リレーションシップ・キャッシングが行われると、accountBeanとaddressBeanの双方をロードする1つの問合せがコードの1行目で発行されるため、パフォーマンスは向上するはずです。したがって、ある特定のファインダ・メソッドの実行後に関連のBeanへのアクセスがあることが分かっている場合は、リレーションシップ・キャッシング機能によってそれをファインダ・メソッドに知らせることをお薦めします。
リレーションシップ・キャッシングの機能には次のような制限があります。
リレーションシップ・キャッシングは、one-to-one、one-to-many、およびmany-to-oneの関係でサポートされます。many-to-manyの関係ではサポートされていません。
weblogic-qlを使用した場合、この機能は、EJBObject BeanまたはEJBLocalObject Beanへの参照を返すファインダ・メソッドを使ったときのみ機能します。
ファインダ・メソッドまたは選択メソッドでリレーションシップ・キャッシングを有効にする場合、問合せの結果は、たとえdistinctキーワードを指定していなくても常に異なる集合になります。これは、EJBコンテナが基底のJDBC結果セットで重複を区別できないようにする技術的な限界によるものです。
リレーションシップ・キャッシングが有効な場合は、関係に変更を加えるとそれが自動的にキャッシュでも反映されます。たとえば、1対多の関係の「多」サイドでインスタンスが追加されると、その変更はキャッシュ内の関係でも反映されます。関係の「1」サイドにあるBeanに対してそれ以降問合せを行うと、新しいインスタンスがその問合せから利用可能なように関係がキャッシュで更新されます。
リレーションシップ・キャッシングを有効化するには、次の手順に従います。
weblogic-cmp-jar.xmlファイルのweblogic-query要素でcaching-name要素を指定します。
weblogic-query要素でcaching-name要素が指定されている場合、ファインダ問合せが実行されると、WebLogic Serverはcaching-name要素が指定するrelationship-caching要素の指定に従って関連するBeanのデータをロードします。
ファインダを格納するBeanのfinders-load-bean要素(weblogic-ejb-jar.xml)が、Falseに設定されていないようにします。Falseの場合は、リレーションシップ・キャッシングが有効になりません。finder-load-beanのデフォルト値はTrueです。
weblogic-cmp-jar.xmlファイルでdatabase-type要素を指定します。リレーションシップ・キャッシングは問合せに外部結合を使用し、外部結合の構文はデータベースのタイプによって異なります。
リレーションシップ・キャッシングは結合問合せを使用するので、relationship-caching要素のcaching-element要素の数は結果セットの重複を増加させる場合があります。caching-elementごとに1つずつ1対多の関係を指定すると、結果セットで重複を回避できます。
次の例のように、weblogic-cmp-jar.xmlでrelationship-caching要素を指定します。
<relationship-caching>
<caching-name>cacheMoreBeans</caching-name>
<caching-element>
<cmr-field>accounts</cmr-field>
<group-name>acct_group</group-name>
<caching-element>
<cmr-field>address</cmr-field>
<group-name>addr_group</group-name>
</caching-element>
</caching-element>
<caching-element>
<cmr-field>phone</cmr-field>
<group-name>phone_group</group-name>
</caching-element>
</relationship-caching>
accountsフィールドとphoneフィールドはcustomerBeanのcmrフィールド、addressフィールドはaccountBeanのcmrフィールド、addr_groupとphone_groupはaddressBeanとphoneBeanのグループです。
caching-element要素をネストすることにより、関係するBeanを複数レベルでロードできるようになります。上記のサンプルでは、addressBeanがaccountBean内でネストになっているので、第2レベルの関連Beanにあたります。現在、指定できるcaching-elementの数に制限はありません。しかし、caching-elementのレベルをあまり多く設定しすぎると、そのトランザクションのパフォーマンスに影響すると考えられます。
エンティティBeanの同時実行性ストラテジは、EJBコンテナがBeanへの同時アクセスをどのように管理するのかを指定します。つまり、WebLogic Serverが、エンティティのキャッシュされたコピーとデータベースをいつどのように同期させるのかを指定します。
WebLogic Serverでサポートされている同時実行性については、以降の節で説明します。
排他的同時実行性の場合、コンテナはBeanがトランザクションに関連付けられている場合に、キャッシュされたEJBインスタンスを排他的にロックします。EJBインスタンスに対する要求は、トランザクションが完了するまでブロックされます。排他的なロックはサーバー・インスタンスでローカルに行われるので、この方式は単一サーバー・アーキテクチャに最も適しています。クラスタで使用した場合、排他的同時実行性はサーバー・インスタンス内でBeanインスタンスに対する要求をすべてシリアライズしますが、同じBeanに同時にアクセスするクラスタ内のサーバー間の同時実行性はデータベースによって管理されます。
複数のクライアントが排他的同時実行性オプションを使用して、エンティティEJBに連続してアクセスできます。この排他的オプションを使用する場合、2つのクライアントでエンティティEJBの同じインスタンス(主キーが同じインスタンス)へのアクセスが同時に試行されると、2番目のクライアントはEJBが利用可能になるまでブロックされます。
データベース同時実行性を使用する場合、各トランザクションのEJBの同時実行性制御は基底のデータベースに委ねられます。WebLogic Serverは、独立したエンティティBeanインスタンスを各トランザクションに割り当て、同時実行性制御をデータベースで処理できるにようにします。これは現在のデフォルト・オプションです。
Database メカニズムでは、EJBコンテナが継続してエンティティBeanのインスタンスをキャッシュします。しかし、コンテナはトランザクション間のBeanインスタンスの中間状態をキャッシュしません。その代わりとして、WebLogic Serverは、トランザクションの開始時に各インスタンスに対しSQL SELECTを発行して最新のEJBデータを取得します。SQL UPDATEは、変更がある場合に発行されます。
続いて、データのコミット要求がデータベースに送られます。このためデータベースは、EJBのデータの同時実行性制御とデッドロックの検出をすべて処理します。
Database同時実行性ストラテジの場合と同じように、Optimistic同時実行性ストラテジでは各トランザクションにそれ専用のBeanインスタンスが割り当てられます。Optimistic同時実行性ストラテジは、トランザクションの実行中、EJBコンテナまたはデータベースでどのようなロックも行いません。
|
注意: 読込みロックを行うデータベース(Oracle以外のデータベース)では、オプティミスティックなBeanは独立したローカルのトランザクションでデータを読み込みます。そのローカル・トランザクションは、読込みが完了するとすぐコミットされます。この方式では読込みロックが回避され、複数のトランザクションが同じデータを同時に更新しない場合にスケーラビリティを向上させることができます。 |
オプティミスティックなデータが古くなるのを防ぐために、コンテナはトランザクションごとに新しいBeanインスタンスをアクティブ化して、複数の要求を並行処理します。cache-between-transactionsの値がTrueの場合、WebLogic Serverはread-timeout-secondsの値に基づいてエンティティBeanのejbLoad()を呼び出します。
基底データがEJBコンテナの外部で更新された場合、オプティミスティックなBeanを明示的に無効にできます(「バックドア更新」とも呼ぶ)。詳細については、「エンティティEJBの明示的な無効化」を参照してください。
デフォルトによって、concurrency-strategyがOptimisticであるBeanがクラスタにデプロイされており、クラスタのメンバーがそのBeanを更新した場合、EJBコンテナは、クラスタ内のすべてのサーバーに存在するそのBeanのすべてのコピーを無効にしようとします。この無効化の処理によって、オプティミスティック同時実行性の失敗を防ぐことができます。しかし、この処理はリソースを大量に消費するため、パフォーマンスが低下する可能性があります。必要な場合、weblogic-cmp-jar.xmlのcluster-invalidation-disabledをTrueに設定して、EJBコンテナがクラスタ内のBeanのコピーを無効化しないようにできます。
トランザクションで読み込みまたは更新されたデータが別のトランザクションで変更されていないことを検証するために、トランザクションのコミットの前にオプティミスティックなBeanのトランザクション・データを検証するようにEJBコンテナを構成できます。データの変更が検出された場合、EJBコンテナはトランザクションをロールバックします。
|
注意: EJBコンテナは、 |
Optimistic同時実行性のBeanの有効性チェックを構成するには、weblogic-cmp-jar.xmlファイルのそのBeanのtable-map要素でverify-columns要素とverify-rows要素を使用します。
verify-rows要素は、オプティミスティック同時実行性の使用時にEJBコンテナがチェックすべきである、表内の行を指定します。verify-columns要素は、オプティミスティック同時実行性ストラテジを使用する場合に、表の列の有効性がどのようにチェックされるのかを指定します。
verify-rows要素の設定値は以下のとおりです。
Read - トランザクションの間に参照した表のすべての行をチェックします。これには、単に読み込まれるだけの行と、読み込まれた後でトランザクションによって更新または削除される行の両方が含まれます。すべての行をチェックすると、通常はEJBコンテナで実行しなければならないオプティミスティック・チェックの量が増えるのでオーバーヘッドが大きくなります。Readオプションを使用する場合、コミットされたトランザクションは、トランザクションがコミットされるまで別のトランザクションで修正されることのない行を読み込みます。その結果として、SERIALIZABLEの一貫性のANSI定義と非常に近い高度な一貫性が実現します。
Modified - 現在のトランザクションで更新または削除した行だけをチェックします。この設定にすると、2つのトランザクションが同時に同じ行を更新することがなく、更新が損失することはありませんが、異なるトランザクションで読込みと更新を交互に行うことは可能です。その結果、得られる一貫性のレベルは、ANSIのREAD_COMMITTEDレベルとREPEATABLE_READレベルの間になります。
verify-columns要素の設定値は以下のとおりです。
Read - トランザクションの間に参照した表のすべての列をチェックします。これには、単に読み込まれるだけの行と、読み込まれた後でトランザクションによって更新または削除される行の両方が含まれます。
Modified - 現在のトランザクションで更新または削除した列だけをチェックします。
|
注意:
|
Version - 表にバージョン列が含まれ、この列がオプティミスティック同時実行性を実施するのに使われていることをチェックします。
Version列は、初期値0または正の整数で作成し、行が変更される度に1ずつ加算されるようにしてください。詳細については、「version-column-initial-value」を参照してください。
また、データベース・トリガーを使用してデータベース内のバージョン列を更新し、trigger-updates-optimistic-columnをTrueに設定した場合、データベース・トリガーはBeanの作成時にデータベース内のバージョン列を初期化する必要があります。
Timestamp - 表にタイムスタンプ列が含まれ、この列がオプティミスティック同時実行性を実施するのに使われていることをチェックします。タイムスタンプ・ベースのオプティミスティック同時実行性では、このデータベース列の粒度を1秒にする必要があります。
デフォルトによって、EJBコンテナはバージョンおよびタイムスタンプ列を管理し、これらの列を常に最新の状態に保ちます。代わりに、データベース・トリガーによってバージョンおよびタイムスタンプ列が管理されるようにする場合、trigger-updates-optimistic-columnの値をTrueに設定します。
|
注意: バージョンまたはタイムスタンプ列は、トランザクションが通常のCMPまたはCMRフィールドを修正しなかった場合は更新されません。トランザクションの過程で変更された唯一のデータがバージョンまたはタイムスタンプ列の値である場合(トランザクションの開始の結果として)、オプティミスティック・チェックで使用される列はトランザクションの最後に更新されません。 |
verify-columnsがVersionまたはTimestampに設定されている場合、以下のことを行います。
weblogic-cmp-jar.xmlファイルのtable-map要素のoptimistic-columnを使用してバージョンまたはタイムスタンプ列を指定します。この列をcmp-fieldにマップするかどうかは任意です。
optimistic-column要素は、オプティミスティック同時実行性を実装するためのバージョン値またはタイムスタンプ値を格納するデータベース列を示します。すべてのデータベースで大文字と小文字が区別されるわけではありませんが、この要素では大文字と小文字がそのまま維持されます。この要素の値は、verify-columnsがVersionまたはTimestampに設定されていない場合は無視されます。
weblogic-cmp-jar.xmlファイルのversion-column-initial-value要素を使用してバージョン列の初期値を指定します。
EJBが複数の表にマップされる場合、トランザクション中に更新した表に対してのみオプティミスティックなチェックが実行されます。
Oracleデータベースでは、CMPのキー以外のフィールドの型がjava.util.Dateで実装型がOracle DATEであるエンティティEJBでverify-columnsをModifiedに設定すると、キーではないDATEフィールドに対して単純な更新が行われたときに、たとえ1人のユーザーしかレコードを更新していなくてもWebLogic Serverがオプティミスティック同時実行性の違反例外を送出します。
この問題は、Oracle DATE列とjava.util.Date型の日付値の精度が異なるために発生します。java.util.Date型はミリ秒単位ですが、Oracle DATE列は違います。このエラーは、以下の2通りの方法で防止できます。
Oracleデータベースの列の型をTimestamp (Oracle9iで導入されたより精度の高い型)に設定します。
java.util.Date値のミリ秒を削除するロジックをアプリケーションに追加します。そのためには、次のようにしてエンティティBeanのjava.util.Dateフィールドに合わせて日付フィールドを準備します。
Calendar cal = Calendar.getInstance(); cal.set(Calendar.MILLISECOND, 0); // clears millisecond Date myDate = cal.getTime();
Beanが読取り専用であることを示すために使用します。コンテナは、複数の要求が並行して処理されるように各トランザクションで新しいBeanインスタンスをアクティブ化します。WebLogic Serverは、read-timeout-secondsパラメータに基づいて読取り専用BeanのejbLoad()を呼び出します。
このリリースのWebLogic Serverでは、読取り専用Beanのコードを効率化するために、ReadOnly同時実行性を使用するEJBで作成と削除は許可されていません。
読取り専用Beanが作成および削除操作を使用できるようにするには、weblogic-cmp-jar.xmlのallow-readonly-create-and-remove要素をTrueに設定します。
同時実行性は、パフォーマンスとデータの鮮度の間でトレードオフを生じさせます。アプリケーションでどの要素がより重要であるかに基づいて、同時実行性ストラテジを選択してください。トレードオフについては、表6-5を参照してください。
表6-5 同時実行性ストラテジのトレードオフ
| 同時実行性ストラテジ | メリット | リスクと制限 | 選択する場合 |
|---|---|---|---|
|
|
同時実行性制御をデータベースに委ねると、データへの同時アクセスの点で排他的同時実行性と比べてスループットが向上するとともに、デッドロックが検出されるようになります。 |
デッドロックのリスクがあります。各トランザクションがデータベースから更新ロックを取得する必要があるため。 デッドロックのリスクを小さくするには、次で
Beanのデータベースのロック・ポリシーに対する依存度を高めます。Beanの移植性が低下する場合があります。 |
データベース同時実行性の制御がアプリケーションにとって十分であり、コンテナ提供の追加機能が必要ない場合。 注意 : |
|
|
トランザクションの間にEJBコンテナまたはデータベースでロックが行われないため、最高レベルの同時アクセスが実現します。 |
複数のトランザクションが同時に同じアプリケーション・データにアクセスできます。 |
複数のトランザクションが同時に同じアプリケーション・データを修正することが考えられない場合。 |
|
|
高度な一貫性を実現するために、単一サーバー(クラスタ化されていない環境)でEJBデータへのアクセスをシリアライズします。ロックのアップグレードに起因するデッドロックを回避し、 |
パフォーマンスが低下することがあります。いったんクライアントがEJBインスタンスをロックすると、他のクライアントは読込みアクセスのみが必要な場合でもそのEJBのデータからブロックされてしまいます。 |
この方式に依存するアプリケーションに下位互換性を提供する場合。 高レベルの同時実行性が不可欠で、それがパフォーマンスよりも重要であるアプリケーションで使用します。 |
|
|
なし |
なし |
なし |
Beanで同時実行性メカニズムを指定するには、weblogic-ejb-jar.xmlでentity-cache要素のconcurrency-strategy要素を設定します。concurrency-strategyはBeanレベルで定義されるので、同じアプリケーションでも異なるBeanは必要に応じて別々の同時実行性を使用できます。
concurrency-strategyを指定しない場合、WebLogic ServerはデフォルトでDatabase同時実行性を使用します。
スループットが高い状況では、カスケード削除を実行するトランザクションが、カスケード削除を実行しないトランザクションと同じエンティティBeanにアクセスする必要がある場合に、排他的同時実行性ストラテジを使用するトランザクションでデッドロックが発生する可能性があります。
このようなデッドロックは、weblogic-cmp-jar.xmlデプロイメント記述子ファイルのlock-order要素を使用して回避できます。lock-orderは、関連するBeanのカスケード削除の過程でBeanがロックされる順序を定義します。その値は、整数値です。lock-orderの値が最低のBeanは最初に処理され、次に低いlock-order値のBeanがその次に処理されます。
指定するロックの順序は、アプリケーションの他のトランザクションで使用されるロックの順序と同じでなければなりません。
lock-orderを指定すると、他のトランザクションと同じ順序でカスケード削除がBeanインスタンスをロックします。通常のロック順序がBeanA、BeanBの順である場合に、このlock-orderを指定すると、カスケード削除でもその順序が使用されます。
あまり更新されない永続データの場合は、読取り専用エンティティBeanと読み書き対応エンティティBeanを同じデータにマップすることでWebLogic Serverで「read-mostlyパターン」を実装できます。読取り専用エンティティBeanは読込みに、読み書き対応エンティティBeanは書込みに使用します。
読取り専用エンティティEJBは、weblogic-ejb-jar.xmlでそのBeanのentity-cache (またはentity-cache-ref)要素のread-timeout-seconds要素に指定された間隔でBeanのデータをロードします。読取り専用Beanが常に最新のデータを返すようにするには、読み書き対応BeanがエンティティBeanのデータを変更するときに読取り専用Beanを無効にする必要があります。WebLogic Serverが読取り専用Beanを自動的に無効化するように構成するか、Beanコードで明示的に無効化することができます。詳細については、それぞれ「読取り専用エンティティEJBの暗黙的な無効化」および「エンティティEJBの明示的な無効化」を参照してください。
WebLogic Serverクラスタでread-mostlyパターンを利用すると、読取り専用EJBのクライアントではキャッシュからの読込みでパフォーマンスが向上し、読み書き対応EJBのクライアントでは真のトランザクション動作が実現します(read-write EJBのキャッシュされた状態が常にデータベースの永続データと一致します)。
以下のプラクティスを行うと、read-mostlyパターンでデータ一貫性の問題が発生する可能性が低下します。
weblogic-ejb-jar.xmlでの読取り専用Beanのread-timeout-seconds要素の構成
同じトランザクションで更新できるすべてのBeanで同じ値に設定します。
許容可能なパフォーマンス・レベルになる最短の期間に設定します。
読み書き対応Beanの設計
必要最低限のデータ・セットを更新するようにします。ejbStore()のたびに変更のない多くのフィールドをデータ・ストアに書き込むBeanを実装しないようにします。
データを適時に更新するようにします。読取り専用Beanのread-timeout-seconds設定を超える時間の長いトランザクションでは読み書き対応Beanを使用しないようにします。
読み書き対応BeanがBeanのデータを更新するときに読み書き対応Beanに対応する読取り専用Beanを無効化します。
EJB 2.xを実行する場合は、オプティミスティック同時実行性を使用する単一Beanでread-mostlyパターンを模倣することができます。オプティミスティックなBeanは、読込みを実行するときに読取り専用Beanのように機能します(キャッシュから読み込み、古いデータを返すことがあります)。ただし、オプティミスティックなBeanが書込みを実行するときは、コンテナによって更新対象のデータが変更されていないようにします(データベース同時実行性を使用するBeanと同じレベルの書込みの一貫性が提供されます)。「同時実行性ストラテジの選択」を参照してください。
weblogic-ejb-jar.xmlのentity-descriptor要素のinvalidation-target要素は、CMPエンティティBeanが修正されたときに無効化すべき読取り専用エンティティEJBを特定します。
invalidation-targetは、EJB 2.x CMPエンティティBeanでのみ指定できます。ターゲットのejb-nameは、読取り専用エンティティEJBでなければなりません。
このリリースのWebLogic Serverでは、cache-between-transactionsが有効化されているオプティミスティックなエンティティBeanを無効化できます。そのためには、CachingHomeまたはCachingLocalHomeインタフェースの次のinvalidate()メソッドを呼び出します。
例6-10 CachingHomeインタフェースとCachingLocalHomeインタフェース
package weblogic.ejb;
public interface CachingHome {
public void invalidate(Object pk) throws RemoteException;
public void invalidate (Collection pks) throws RemoteException;
public void invalidateAll() throws RemoteException;
public interface CachingLocalHome {
public void invalidate(Object pk) throws RemoteException;
public void invalidate (Collection pks) throws RemoteException;
public void invalidateAll() throws RemoteException
}
次のサンプル・コードは、ホームをCachingHomeにキャストしてからメソッドを呼び出す方法を示したものです。
例6-11 ホームのキャストとメソッドの呼出し
import javax.naming.InitialContext;
import weblogic.ejb.CachingHome;
Context initial = new InitialContext();
Object o = initial.lookup("CustomerEJB_CustomerHome");
CustomerHome customerHome = (CustomerHome)o;
CachingHome customerCaching = (CachingHome)customerHome;
customerCaching.invalidateAll();
invalidate()メソッドを呼び出すと、エンティティBeanはローカル・サーバー・インスタンスで無効化されます。サーバー・インスタンスがクラスタに属している場合は、Beanのキャッシュされたコピーを無効化するように他のクラスタ化されたサーバーにメッセージがマルチキャストされます。無効化された読取り専用エンティティBeanに対して次にgetXXX()が呼び出されたときには、コンテナはBeanの永続データの最新バージョンをデータベースからエンティティ・キャッシュにロードします(「ejbLoad()とejbStore()の動作について」を参照)。
WebLogic Serverは、更新トランザクションの完了後にinvalidate()を呼び出します。トランザクションの更新中に無効化処理が行われた場合、トランザクションのisolation-levelでコミットされていないデータの読出しが許可されていないと、更新前のデータが読み出される可能性があります。
以下の節では、CMPエンティティBeanのWebLogic Server固有のデプロイメントを簡単に参照できます。各節では、特定のタイプの機能または動作に関連する要素が取り上げられています。各節の表では、制御する動作、その要素が含まれるweblogic-cmp-jar.xmlの親要素、およびweblogic-cmp-jar.xmlで明示的に指定しない場合に予想される動作に基づいて関連要素が定義されています。
次の表に、weblogic-cmp-jar.xmlのコンテナ管理による関係要素を示します。
表6-6 weblogic-cmp-jar.xmlのコンテナ管理による関係要素
| 要素 | 説明 |
|---|---|
|
|
関係の名前。 注意: 関係の |
|
|
関係ロールの名前。(関係には、各サイドに1つで2つのロールがあります。) 1対1または1対多の関係の場合は、 多対多の関係の場合は、関係の両側でロールを指定します。例については、「多対多の関係の定義」を参照してください。 注意 :
|
|
|
関係のキー列マッピングのターゲット側を指定します(外部キー列)。 |
|
|
関係のキー列マッピングの開始側を指定します(主キー列)。 |