Oracle® Fusion Middleware Oracle WebLogic Server Enterprise JavaBeansバージョン2.1の開発 12c (12.2.1) E69966-01 |
|
![]() 前 |
![]() 次 |
この章では、アプリケーションでエンティティ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では、管理者は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用にスペースが必要になるまでキャッシュにとどまります。
WebLogic Server管理コンソールの「モニタリング」タブの現在のキャッシュ済Bean数フィールドには、READYおよびACTIVE Beanの数が表示されます。また、このリリースのWebLogic Serverでは、管理者は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で使用する場合、ejbLoad() は怠惰なロードを実行しません。それらのBeanタイプの場合、Beanの永続データはejbLoad()の間に キャッシュにロードされます。 |
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 列の含まれるSQL Server表作成の手順については、Microsoftのドキュメントを参照してください。 |
表で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が変更されたときに自動的に基底の表スキーマを変更するように構成できます。そのように構成すると、表はオブジェクトの関係の最新のマッピングを常に反映するようになります。
注意: この機能は、サーバー・インスタンスがプロダクション・モードで実行されている場合は無効です。プロダクション環境では、より正確な表スキーマ定義を使用することが必要な場合があるからです。確実にコンテナによって作成された表だけが変更されるように、コンテナで作成された表には、wls_temp という追加列が含まれています。 |
表作成文の構文(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に子があるかどうかが確認されません。duplicationKeyException データベース例外を防止するには、データベースの子表で外部キー制約を設定する必要があります。 |
問題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コンテナ外の別のアプリケーションで更新されることはあってはなりません。
注意: Exclusive 同時実行性のBeanがクラスタにデプロイされた場合、長期キャッシングが自動的に無効になります。クラスタ内では、どのサーバー・インスタンスもBeanデータを更新できるからです。このため、トランザクション間のキャッシングは不可能になります。 |
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()
を呼び出すようになります。
注意: delay-updates-until-end-of-tx をfalse に設定すると、各メソッド呼出しの後にデータベースの更新が行われますが、その更新はトランザクションが終わるまでコミットされません。 |
動的問合せを使用すると、各自のアプリケーション・コードで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>
注意: cascade-delete 要素は、関係のもう片方のejb-relationship-role でmultiplicity がone に設定されている場合にのみejb-relationship-role 要素で指定できます。 |
データベース・レベルのカスケード削除(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のBlobまたはClobフィールドを検証しません。これを回避するには、バージョン・チェックまたはタイムスタンプ・チェックを行います。 |
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
- 現在のトランザクションで更新または削除した列だけをチェックします。
注意: verify-rows がRead に設定されていると、verify-columns 要素では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対多の関係の場合は、 多対多の関係の場合は、関係の両側でロールを指定します。例については、「多対多の関係の定義」を参照してください。 注意 :
|
|
関係のキー列マッピングのターゲット側を指定します(外部キー列)。 |
|
関係のキー列マッピングの開始側を指定します(主キー列)。 |