WebLogic エンタープライズ JavaBeans (EJB) プログラマーズ ガイド
この章では、アプリケーションでエンティティ Bean をプログラミングおよび使用するための WebLogic Server の付加価値機能について説明し、関連する設計および開発上のガイドラインを示します。
この章は、Java のプログラミングおよびエンティティ Bean の機能に精通している読者を対象としています。 エンティティ Bean の概要およびエンティティ Bean のアプリケーションでの典型的な使用方法については、「エンティティ EJB による永続データの保持」および「エンティティ Bean の機能」を参照してください。
Bean 開発の全体的なプロセスについては、「エンタープライズ JavaBean の実装」を参照してください。
WebLogic Server には、エンティティ EJB のパフォーマンスとスループットを向上させる以下の機能があります。
図 6-1 は、エンティティ Bean インスタンスのライフサイクルを示しています。この節では、コンテナがどのようにしてフリー プールとキャッシュを処理および管理するのかを説明します。
weblogic-ejb-jar.xml
で initial-beans-in-free-pool 要素にゼロ以外の値を指定すると、WebLogic Server は起動時に指定された量の Bean インスタンスをプールに格納します。
initial-beans-in-free-pool
のデフォルト値はゼロです。起動時に Bean インスタンスをフリー プールに格納しておくと、リクエストが来てから新しいインスタンスを生成せずに Bean に対する初期リクエストが可能になるため、EJB の初期応答時間が短縮されます。
フリー プールからエンティティ Bean のインスタンスを取得しようとすると、その試みはプールが空の場合でも必ず成功します。プールが空の場合は、新しい Bean インスタンスが作成されて返されます。
POOLED Bean は匿名インスタンスであり、ファインダおよびホーム メソッドで使用されます。プールに格納できるインスタンスの最大数は、weblogic-ejb-jar.xml
の max-beans-in-free-pool 要素で指定します (デフォルト設定は 1,000)。
Bean でビジネス メソッドが呼び出されると、コンテナはプールからインスタンスを取得し、ejbActivate
を呼び出して、そのインスタンスがメソッド呼び出しに対応します。
READY インスタンスはキャッシュにあり、ID (関連付けられた主キー) を持ちますが、現時点ではトランザクションに登録されていません。READY エンティティ EJB のインスタンスは、最長時間未使用 (LRU) の順で維持されます。
ACTIVE インスタンスは、現時点でトランザクションに登録されています。トランザクションの完了後、そのインスタンスは READY になり、他の Bean 用にスペースが必要になるまでキャッシュにとどまります。
[モニタ] タブの [Current Beans in Cache] フィールドには、READY Bean と ACTIVE Bean の数が表示されます。
max-beans-in-cache 要素の効果とキャッシュで許可される主キーが同じインスタンスの数は、同時方式によって異なります。表 6-1 は、同時方式ごとに、weblogic-ejb-jar.xml
の max-beans-in-cache 要素の値がキャッシュ内のエンティティ Bean インスタンスの数をどのように制限するのか、および同じ主キーでエンティティ Bean インスタンスがいくつキャッシュ内で許可されるのかを示しています。
表 6-1 同時方式別のエンティティ EJB のキャッシング動作
READY のエンティティ EJB インスタンスは、他の Bean でスペースが必要なときにキャッシュから削除されます。READY インスタンスがキャッシュから削除され、Bean で ejbPassivate
が呼び出されて、コンテナがそのインスタンスをフリー プールに戻そうとします。
コンテナがインスタンスをフリー プールに戻そうとしたときに、プールがすでに max-beans-in-free-pool 数のインスタンスで満たされている場合、インスタンスは破棄されます。
ACTIVE のエンティティ EJB インスタンスは、そのインスタンスが参加しているトランザクションがコミットまたはロールバックされるまでキャッシュから削除されません。トランザクションがコミットまたはロールバックされた時点で、インスタンスは READY になり、キャッシュから削除できるようになります。
この節では、CMP 2.0 エンティティ Bean の永続データがいつどのようにしてキャッシュにロードされ、永続ストレージに書き込まれるのかを説明します。
findXXX()
- デフォルトでは、CMP Bean でファインダ メソッドを呼び出すと、Bean の永続データがすぐにキャッシュにロードされます。この動作は、weblogic-ejb-jar.xml
の persistence スタンザの finders-load-bean 要素で制御します。ejbLoad()
- CMP 2.0 エンティティ 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 の永続フィールドをデータベースに書き込みます。 複数のクライアントが Bean の基盤データにアクセスして修正できるアプリケーションの場合、「ejbLoad() と ejbStore() の動作について」で説明されている ejbLoad()
と ejbStore()
のデフォルトの動作では、以下のようにしてデータベースの整合性が確保されます。
ただし、要件によっては、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
の場合、コンテナはトランザクションの変更をすべてデータベースにフラッシュしてから新しいクエリを実行します。
トランザクションが修正されたデータのクエリを再実行しない場合は (一般的なシナリオ) キャッシュのフラッシュを安全にオフにして、最高のパフォーマンスを得ることができます。
注意 : WebLogic Server 8.1 より前のリリースでは、include-updates
のデフォルト設定は False
でした。J2EE に準拠するため、このデフォルト設定は WebLogic Server 8.1 から True
に変更されています。
アプリケーションレベルのキャッシング「組み合わせキャッシング」とも呼ばれます。同じ J2EE アプリケーションに属する複数のエンティティ Bean が 1 つの実行時キャッシュを共有できます。各キャッシュを何個のエンティティ Bean が参照するかについて制限はありません。
アプリケーションレベルのキャッシングには以下の利点があります。
ただし、アプリケーションレベルのキャッシングは、スループットの高いアプリケーションにとっては最適な選択肢ではありません。 1 つのキャッシュにつき一度に 1 つの制御スレッドしかないので、スループットが高い場合は、複数のタスクがスレッドの制御を奪い合ってそれがボトルネックになることがあります。
アプリケーションレベルのキャッシュをコンフィグレーションするには、次の手順に従います。
weblogic-application.xml
の entity-cache
スタンザでアプリケーションレベルのキャッシュを定義します。このスタンザとその要素の定義については、『WebLogic Server アプリケーションの開発』の「entity-cache」を参照してください。
weblogic-application.xml
で指定されているアプリケーション レベルのキャッシュの名前でなければならない。weblogic-application.xml
の caching-strategy
と一致していなければならない。読み込み専用エンティティは、マルチバージョンのアプリケーション レベル キャッシュのみを使用できます。詳細については、『WebLogic Server アプリケーションの開発』の「caching-strategy」を参照してください。weblogic-application.xml
デプロイメント記述子については、『WebLogic Server アプリケーションの開発』の「application.xml デプロイメント記述子の要素」に説明があります。
すべてのエンティティ EJB には、そのホームでエンティティ Bean をユニークに識別する主キーが必要です。個々のエンティティ Bean インスタンスは、その主キーに対して別のクラスを定義できます (複数のエンティティ Bean が必要に応じて同じ主キー クラスを使用できる)。
2 つのエンティティ Bean インスタンスのホームと主キーが共通する場合、両者は同一のものと見なされます。クライアントはエンティティ Bean インスタンスのリモート インタフェースへの参照に対して getPrimaryKey()
メソッドを呼び出して、そのホーム内でのインスタンスの ID を調べることができます。
参照と関連付けられたインスタンス ID は、参照が有効な間は変化しません。したがって getPrimaryKey()
メソッドは、同じエンティティ オブジェクトの参照に対して呼び出されたときは常に同じ値を返します。エンティティ オブジェクトの主キーを知っているクライアントは、Bean のホーム インタフェースの findByPrimaryKey(key)
メソッドを呼び出すことによって、エンティティ オブジェクトへの参照を取得することができます。
エンティティ 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 つまたは複数のフィールドに対応する独自の主キー クラスを定義することができます。主キー クラスは public
でなければならず、パラメータを付けない public
コンストラクタを持たなければなりません。ejb-jar.xml
の prim-key-class
要素で主キー クラスの名前を指定します。主キー クラスのすべてのフィールドは public
でなければならず、ejb-jar.xml
および weblogic-ejb-jar.xml
の対応する cmp-field
と同じで名前を持つ必要があります。複数の CMP フィールドに対応する複合主キーの場合は、ejb-jar.xml
で primkey-field
を指定しません。
エンティティ Bean が無名主キークラスを使用する場合、EJB をサブクラス化し java.lang.Integer
型の cmp-field
をそのサブクラスに追加する必要があります。そのフィールドの自動主キー生成を有効にし、コンテナがフィールドの値を自動的に埋め、そのフィールドを weblogic-cmp-jar.xml
デプロイメント記述子のデータベース カラムにマップできるようにします。
最終的に、ejb-jar.xml
ファイルを更新して元の EJB クラスではなく EJB サブクラスを指定するようにし、その Bean を WebLogic Server にデプロイします。
注意 : 元の EJB を無名主キー クラスとともに使用した場合、デプロイメント時に WebLogic Server から次のエラー メッセージが表示されます。
In EJB ejb_name, an 'Unknown Primary Key Class' ( <prim-key-class> == java.lang.Object ) MUST be specified at Deployment time (as something other than java.lang.Object).
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 でエラーが発生します。 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 データベースのみでサポートされています。「主キー フィールドの型の宣言」の手順も参照してください。どちらの方法を使用する場合でも、「主キー フィールドの型の宣言」の手順を使用してください。
Oracle データベース用の主キー生成サポートでは、Oracle データベースの SEQUENCE
エンティティを使用してユニークな主キーを生成します。Oracle SEQUENCE
は、新しい数値が必要な場合に呼び出されます。自動キー生成は、weblogic-cmp-jar.xml
の automatic-key-generation 要素で指定します。generator-name 要素で、Oracle SEQUENCE
の名前を指定します。Oracle SEQUENCE
が SEQUENCE INCREMENT
で作成された場合は、key-cache-size を指定します。key-cache-size
の値は、Oracle SEQUENCE INCREMENT
の値と同じでなければなりません。2 つの値が違う場合は、キーが重複することがあります。
主キーの生成で Oracle SEQUENCE
オブジェクトを使用する場合は、以下の点に注意してください。
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.
SEQUENCE
スキーマ オブジェクトに対応する Oracle の同様の機能をサポートしていない。SEQUENCE
と同様の機能を使用するアプリケーションを旧バージョンの WebLogic Server から WebLogic Server 8.1 に移行すると、以下のエラーが生じます。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>
<generator_name>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
メソッドで、主キー フィールドの型を以下のいずれかとして宣言します。
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 になります。
この節では、エンティティ 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-1CMP エンティティの 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-2CMP エンティティの 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> を使用した自動テーブル作成動作の制御
注意 : シーケンス テーブル、結合テーブル、および Oracle SEQUENCE がサポートされています。
weblogic-cmp-jar.xml
の create-default-dbms-tables
要素を使用してこの機能を有効化します。この機能の動作は、次の表で説明するように、要素の値に応じて変わります。この表に示す EJB コンテナのアクションは、デプロイ中に発生します。
CMP Bean を作成するときに発生する場合のあるタイミングの問題のため、WebLogic Server では Bean の作成プロセスのどの時点で Bean がデータベースに挿入されるのかを指定することができます。
cmr-field
は、Bean の主キー値 (ejbPostCreate
が呼び出されて設定される) がアクセス可能になるまで設定できません。したがって、cmr-field
は ejbPostCreate
が呼び出されるまで設定できません。この要因が他の条件と重なると、以下の問題が生じることがあります。
データベースの行が EJBCreate
の後 (つまり、ejbPostCreate
の前) に挿入された場合、外部キーは null 値になります。その理由は、外部キー カラムが cmr-field
の設定時に設定されるからです。
解決策 : weblogic-cmp-jar.xml
の delay-insert-until
を ejbCreate
に設定し (この設定で、挿入は ejbCreate
の直後に行われる)、ejbPostCreate
の過程で関係を設定します。
ejbPostCreate
の過程での Bean の作成関連する Bean が作成されるときに、その Bean のデータベースの挿入が、作成の呼び出しが終了する前に行われます。関連する Bean のデータベース行に、現在の Bean を表す外部キーが含まれており、その外部キーで参照一貫性制約が定義されている場合、挿入は現在の Bean のデータベース行がまだ挿入されていない場合は失敗します。
解決策 : delay-insert-until
を ejbCreate
に設定し、現在の Bean の行が ejbPostCreate
の間存在するようにします。
注意 : 1 対 1 の関係では、親 Bean の主キーが子 Bean の CMR フィールドに埋め込まれている場合、EJB コンテナが Bean を作成するときに、パフォーマンス上の理由からその親 Bean に子があるかどうかが確認されません。duplicationKeyException
データベース例外を防止するには、データベースの子テーブルで外部キー制約を設定する必要があります。
weblogic-cmp-jar.xml
の delay-database-insert-until 要素を使用すると、EJBCreate
メソッドまたは EJBPostCreate
メソッドが終了するまでデータベースの挿入を遅らせることができます。トランザクションの最後に更新を一括で順序付けして実行するには、weblogic-cmp-jar.xml
で enable-batch-operations と order-database-operations の両方を「y
」に設定します。
関連する 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 を参照した後に各トランザクションでキャッシュされたデータを再利用するが、各トランザクションの最後にオプティミスティックな衝突をチェックすることで更新がトランザクションとして一貫性を持つようにする。 注意 : クラスタでは、同時方式が Optimistic の Bean が更新されると、オプティミスティックな衝突を防止するために他のクラスタ メンバーに通知がブロードキャストされます。
表 6-3は、エンティティ Bean のタイプおよび同時方式別のcache-between-transactions
要素の有効値を示しています。
表 6-3 同時方式およびエンティティ タイプ別の 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
に設定すると各メソッド呼び出しの後にデータベースの更新が行われますが、その更新はトランザクションが終わるまでコミットされません。
動的クエリを使用すると、各自のアプリケーション コードでプログラム的にクエリを作成したり実行できるようになります。
次のコード例では、動的クエリをどのように実行するかを示します。
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 Binary Large Object (BLOB) および Character Large Object (CLOB) DBMS カラムを CMP エンティティ Bean でサポートしています。
WebLogic Server は、バイト配列またはシリアライズ可能な型を持つ cmp-field に BLOB をマップします。現時点では、char
配列を CLOB カラムにマップすることはできません。
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>OracleBlob</dbms-column-type>
</field-map>
WebLogic Server 8.1 SP02 より前は、デフォルトで、OracleBlob にマップされた byte[] 型の cmp-field はシリアライズされていました。WebLogic Server 8.1 SP02 では、デフォルトではシリアライズは行われません。
WebLogic Server が OracleBlob にマップされた byte[] 型の cmp-fields をシリアライズするようにするには、WebLogic Server 8.1 SP02 で導入された serialize-byte-array-to-oracle-blob 互換性フラグを設定します。
デフォルトでは、serialize-byte-array-to-oracle-blob
の値は false
です (コンテナが byte[] を直接保持し、シリアライズはしない)。
次の XML コードは、weblogic-cmp-jar-xml
ファイルの dbms-column 要素を使用して CLOB オブジェクトを指定する方法を示しています。
<field-map>
<cmp-field>description</cmp-field>
<dbms-column>product_description</dbms-column>
<dbms_column-type>OracleClob</dbms-column-type>
</field-map>
Oracle 9i と10g ドライバでは、データベース行に CLOB カラム値を正常に挿入するために複数の要件があります。Oracle 9i ドライバでは、データベース行は CLOB 値を挿入する前にロックする必要があります。その結果、Oracle 9i ではテーブルに CLOB カラム値を挿入するために WebLogic Server は次のように動作します。
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」と Oracle の製品マニュアルを参照してください。
フィールド グループは、Bean のコンテナ管理による永続性 (CMP) フィールドとコンテナ管理による関係 (CMR) フィールドのサブセットを表します。パフォーマンスを向上させるために、Bean 内の関連フィールドを、障害のあったグループにまとめて 1 つのユニットとしてメモリ内に入れることができます。
グループをクエリまたは関係に関連付けることができます。それによって、クエリを実行するか、または関係に従った結果として Bean がロードされたときに、グループ内の指定フィールドのみがロードされます。
指定したグループを持たないクエリと関係に対して、「default」という特殊なグループを使用します。デフォルトでは、default グループには、Bean のすべての CMP フィールドと、Bean テーブルに外部キーを追加するすべての CMR フィールドが格納されます。
フィールドは複数のグループに関連付けられている場合があります。この場合、フィールドに対して getXXX()
メソッドを実行すると、そのフィールドを含む最初のグループで障害が発生します。
フィールド グループは、コード リスト 6-3 のように weblogic-cmp-jar.xml
のfield-group 要素で指定します。
<weblogic-rdbms-bean>
<ejb-name>XXXBean</ejb-name>
<field-group>
<group-name>medical-data</group-name>
<cmp-field>insurance</cmp-field>
<cmr-field>doctors</cmr-fields>
</field-group>
</weblogic-rdbms-bean>
同じコンテナ管理による永続性 (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 に割り当てられる場合、コンテナは次のように処理を順序付けします。
これで、顧客 A は存在しない販売員を参照しなくなり、データベースの参照整合性エラーが発生しなくなります。
EJB コンテナが関連する Bean のデータベース処理を正しく順序付けするようにするには、weblogic-cmp-jar.xml
の weblogic-rdbms-relation で Bean 間の関係を定義する必要があります。そうしないと、EJB コンテナが更新を実行しようとしたときにデータベースの制約エラーが発生します。
バッチ処理を使用する場合、トランザクションの開始からコミットまでの間にバッチ処理だけが挿入、更新または削除に適用されるように、トランザクションの境界を設定しなければなりません。
バッチ処理は、addBatch()
と executeBatch()
メソッドをサポートしているドライバのみに機能します。サポートされていないドライバを検出すると、EJB コンテナはバッチ処理がサポートされていないことを報告し、バッチ処理を無効化します。
sybase
または sqlServer
に設定されていると、バッチ処理で主キーの自動生成機能を使用できません。これらのタイプのいずれかで自動主キー生成を有効化していた場合、WebLogic Server は自動的にバッチ処理を無効化し、警告を発行します。 weblogic-ejb-jar.xml
の設定値を超えることはできません。 weblogic-cmp-jar.xml
の dbms-column-type 要素で OracleBlob
か OracleClob
を設定した場合、バッチ処理は自動的に無効になります。Blob または Clob カラムがデータベース テーブルに含まれている状況では、時間短縮があまりできないからです。この場合、デフォルトでは WebLogic Server は Bean ごとに挿入を実行します。
コンテナ管理による関係 (CMR) は 2 つのエンティティ EJB 間で定義する関係であり、データベースのテーブル間の関係と似ています。同じ処理タスクに関わる 2 つの EJB 間で CMR を定義した場合、アプリケーションは以下の機能の恩恵を受けることができます。
以降の節では、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 に以下のことを許可しています。
この機能は EJB 2.1 では規定されていないので、リモート インタフェースしか持たず、双方向の関係に参加するか、一方向の関係の対象となるエンティティ Bean は他のアプリケーション サーバには移行できない場合があります。
エンティティ Bean は、別のエンティティ Bean との間で 1 対 1、1 対多、または多対多の関係を持つことができます。
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-4ejb-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>student</cmr-field-name>
<cmr-field-type>java.util.Collection </cmr-field-type>
</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>teacher</cmr-field-name>
<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-5ejb-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>
cmr-field-type
は、関係のもう一方のサイドのカーディナリティによって異なります。関係のもう一方のサイドの <multiplicity>
が Many
の場合、<cmr-field>
は集合であり、コード リスト 6-4 にある関係の StudentEJB
サイドと同様に、<cmr-field-type>
を java.util.Collection
として指定する必要があります。もう一方のサイドの <multiplicity>
が 1
の場合は、cmr-field type
は単一値のオブジェクトです。cmr-field
が単一値のオブジェクトである場合は、cmr-field
-type
を指定する必要はありません。
表 6-4 は、関係のカーディナリティに基づいて、関係の各 Bean のcmr-field
の内容を示しています。
表 6-4 カーディナリティと cmr-field-type
CMR の方向は、関係の各サイドの ejb-relationship-role
スタンザで cmr-field
を含めるかどうかによってコンフィグレーションします。
双方向 CMR では、関係の両サイドの ejb-relationship-role
スタンザに cmr-field
要素がありますwn in コード リスト 6-4 を参照)。
一方向の関係では、関係の role スタンザの片方だけにしか cmr-field
がありません。開始側 EJB の ejb-relationship-role
には cmr-field
がありますが、対象 Bean の role スタンザにはありません。コード リスト 6-5 では、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 の関係と 1 対多の関係では、関係の片側だけで relationship-role-map が定義されます。
1 対 1 の関係の場合、マッピングは片方の Bean の外部キーからもう片方の Bean の主キーです。
図 6-6 は、MentorEJB
と StudentEJB
間の 1 対 1 の関係に対する weblogic-rdbms-relation
スタンザです。<ejb-relation>
は、図 6-5 に示してあります。
コード リスト 6-61 対 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>
<relationship-role-map>
<foreign-key-column>student</foreign-key-column>
<key-column>StudentID/key-column>
</column-map>
</weblogic-relationship-role>
1 対多の関係の場合、マッピングは常に片方の Bean の外部キーから別の Bean の主キーです。1 対多の関係では、外部キーは常に関係の多サイドにある Bean と関連付けられます。
コードリスト 6-7 は、TeacherEJB
と StudentEJB
間の 1 対多の関係に対する weblogic-rdbms-relation
スタンザです。<ejb-relation>
は、図 6-4 に示してあります。
コード リスト 6-71 対多 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>
<relationship-role-map>
<foreign-key-column>student</foreign-key-column>
<key-column>StudentID/key-column>
</column-map>
</weblogic-relationship-role>
多対多の関係では、関係の各サイドで weblogic-relationship-role スタンザを指定します。そのマッピングには、結合テーブルが関わります。結合テーブルの各行には、関係に関与するエンティティの主キーに対応する 2 つの外部キーが格納されます。関係の方向は、関係のデータベース マッピングを指定する方法に影響しません。
コード リスト 6-8 は、2 人の従業員間の友人関係の weblogic-rdbms-relation スタンザを示しています。
FRIENDS
結合テーブルには、first-friend-id
と second-friend-id
という 2 つのカラムがあります。各カラムには、別の従業員の友人である特定の従業員を示す外部キーが格納されます。従業員テーブルの主キー カラムは id
です。例では、従業員 Bean が単一テーブルにマップされているものと想定しています。従業員 Bean が複数のテーブルにマップされている場合は、主キー カラムを格納するテーブルを relationship-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 テーブルにマップできます。
関係のどちら側の 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-91 対 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 フィールドのアクセサ メソッドを使用できるようにするには、ゲッターおよびセッター メソッドのシグネチャをリモート インタフェースに配置します。ただし、Collection データ型の CMR フィールドはリモート インタフェースで公開できません。Collection データ型の CMR フィールドは、ローカル メソッドでのみアクセスできます。
カスケード削除が実行される場合、別の Bean インスタンスとの関係に参加している Bean インスタンスを削除すると、コンテナは自動的に従属するすべての Bean インスタンスも削除します。この機能では、データの整合性を効率的に維持できます。
たとえば、Employee
Bean が Employee_Projects
Bean との間で 1 対多の関係にある場合、Employee
Bean のインスタンスを削除すると Employee_Projects
Bean のインスタンスも削除されます。
指定できるカスケード削除は 1 対 1 関係と 1 対多関係についてであり、多対多関係については指定できません。
WebLogic Server は、2 通りのカスケード削除をサポートしています。
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
要素で指定できます。
db-cascade-delete
が有効になっている場合は、基盤のデータベースをカスケード削除対応に設定する必要があります。WebLogic および Oracle でデータベースのカスケード削除を設定する手順と例については、「db-cascade-delete」を参照してください。 大規模なトランザクション環境では、カスケード削除を実行するトランザクションが、カスケード削除を実行しないトランザクションと同じ Bean にアクセスする必要がある場合に、排他的な同時方式を使用するトランザクションでデッドロックが発生する可能性があります。そのようなデッドロックを回避する方法については、「Exclusive 同時方式およびカスケード削除を使用するトランザクションのデッドロックの回避」を参照してください。
リレーションシップ キャッシング - 「プリフェッチ」または「期待されるリレーションシップ キャッシング」とも呼ばれます。関係する複数 Bean をキャッシュにロードし、それらに結合クエリを発行してクエリの発行回数を削減することによって、エンティティ Bean のパフォーマンスが高められます。Bean の集合が同じ処理単位の中でアクセスされる場合、アプリケーションはそれらを同時にキャッシュにロードする必要があります。
アプリケーションに、次のような関係を持つエンティティ Bean が含まれているとします。
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 へのアクセスがあることが分かっている場合は、リレーションシップ キャッシング機能によってそれをファインダ メソッドに知らせることをお勧めします。
注意 : リレーションシップ キャッシングの機能には次のような制限があります。
ファインダ メソッドまたは選択メソッドでリレーションシップ キャッシングを有効にする場合、クエリの結果は、たとえ 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 のデータをロードします。
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 でサポートされている同時方式については、以降の節で説明します。
Exclusive 同時方式の場合、コンテナは Bean がトランザクションに関連付けられている場合に、キャッシュされた EJB インスタンスを排他的にロックします。EJB インスタンスに対するリクエストは、トランザクションが完了するまでブロックされます。排他的なロックはサーバ インスタンスでローカルに行われるので、この方式は単一サーバ アーキテクチャに最も適しています。クラスタで使用した場合、Exclusive 同時方式はサーバ インスタンス内で Bean インスタンスに対するリクエストをすべてシリアライズしますが、同じ Bean に同時にアクセスするクラスタ内のサーバ間の同時方式はデータベースによって管理されます。
複数のクライアントが Exclusive 同時方式を使用して、エンティティ EJB に連続してアクセスできます。この排他的オプションを使用する場合、2 つのクライアントでエンティティ EJB の同じインスタンス (主キーが同じインスタンス) へのアクセスが同時に試行されると、2 番目のクライアントは EJB が利用可能になるまでブロックされます。
Database 同時方式を使用する場合、各トランザクションの EJB の同時方式の制御は基盤のデータベースに委ねられます。WebLogic Server は、独立したエンティティ Bean インスタンスを各トランザクションに割り当て、同時方式の制御をデータベースで処理できるにようにします。これは現在のデフォルト オプションです。
Database
メカニズムでは、EJB コンテナが継続してエンティティ Bean のインスタンスをキャッシュします。しかし、コンテナはトランザクション間の Bean インスタンスの中間状態をキャッシュしません。その代わりとして、WebLogic Server は、トランザクションの開始時に各インスタンスに対し SQL SELECT
を発行して最新の EJB データを取得します。 SQL UPDATE
は、変更がある場合に発行されます。
続いて、データのコミット リクエストがデータベースに送られます。このためデータベースは、EJB のデータの同時方式の制御とデッドロックの検出をすべて処理します。
Database
同時方式の場合と同じように、Optimistic
同時方式では各トランザクションにそれ専用の Bean インスタンスが割り当てられます。Optimistic
同時方式は、トランザクションの実行中、EJB コンテナまたはデータベースでどのようなロックも行いません。
注意 : 読み込みロックを行うデータベース (Oracle 以外のデータベース) では、オプティミスティックな Bean は独立したローカルのトランザクションでデータを読み込みます。 そのローカル トランザクションは、読み込みが完了するとすぐコミットされます。この方式では読み込みロックが回避され、複数のトランザクションが同じデータを同時に更新しない場合にスケーラビリティを向上させることができます。
トランザクションで読み込みまたは更新されたデータが別のトランザクションで変更されていないことを検証するために、トランザクションのコミットの前にオプティミスティックな Bean のトランザクション データを検証するように EJB コンテナをコンフィグレーションできます。データの変更が検出された場合、EJB コンテナはトランザクションをロールバックします。
注意 : EJB コンテナは、Optimistic
同時方式では Bean の Blob または Clob フィールドを検証しません。これを回避するには、バージョン チェックまたはタイムスタンプ チェックを行います。
Optimistic
同時方式の Bean の有効性チェックをコンフィグレーションするには、weblogic-cmp-jar.xml
ファイルのその Bean の table-map スタンザで verify-columns 要素と verify-rows 要素を使用します。
verify-columns 要素は、Optimistic 同時方式を使用する場合に、テーブルのカラムの有効性がどのようにチェックされるのかを指定します。
Read
- トランザクションの間に参照したテーブルのすべてのカラムをチェックします。これには、単に読み込まれるだけの行と、読み込まれた後でトランザクションによって更新または削除される行の、両方が含まれます。Modified
- 現在のトランザクションで更新または削除したカラムだけをチェックします。Version
- テーブルにバージョン カラムが含まれ、このカラムがオプティミスティックな同時実行性を実施するのに使われていることをチェックします。Timestamp
- テーブルにタイムスタンプ カラムが含まれ、このカラムがオプティミスティックな同時実行性を実施するのに使われていることをチェックします。タイムスタンプ ベースの同時実行性では、このデータベース カラムの粒度を 1 秒にする必要があります。EJB コンテナは、Version および Timestamp カラムを管理し、これらのカラムが常に最新のものであるようにします。
注意 : バージョンまたはタイムスタンプ カラムは、トランザクションが通常の CMP または CMR フィールドを修正しなかった場合は更新されません。トランザクションの過程で変更された唯一のデータがバージョンまたはタイムスタンプ カラムの値である場合 (トランザクションの開始の結果として)、オプティミスティック チェックで使用されるカラムはトランザクションの最後に更新されません。
Read
- トランザクションの間に参照したテーブルのすべての行をチェックします。これには、単に読み込まれるだけの行と、読み込まれた後でトランザクションによって更新または削除される行の、両方が含まれます。すべての行をチェックすると、通常は EJB コンテナで実行しなければならないオプティミスティック チェックの量が増えるのでオーバーヘッドが大きくなります。Read
オプションを使用する場合、コミットされたトランザクションは、トランザクションがコミットされるまで別のトランザクションで修正されることのない行を読み込みます。その結果として、SERIALIZABLE の一貫性の ANSI 定義と非常に近い高度な一貫性が実現します。注意 : verify-rows
が Read
に設定されていると、verify-columns
要素では Modified
を指定できません。この組み合わせでは、修正された行だけがチェックされることになるためです。
Modified
- 現在のトランザクションで更新または削除した行だけをチェックします。 この設定にすると、2 つのトランザクションが同時に同じ行を更新することがなく、更新が損失することはありませんが、異なるトランザクションで読み込みと更新を交互に行うことは可能です。その結果、得られる一貫性のレベルは、ANSI の READ_COMMITTED レベルと REPEATABLE_READ レベルの間になります。verify-columns
が Version
または Timestamp
に設定されている場合は、weblogic-cmp-jar.xml
ファイルの table-map スタンザの optimistic-column を使用してバージョンまたはタイムスタンプ カラムを指定します。このカラムを cmp-field にマップするかは任意です。 EJB が複数のテーブルにマップされる場合、トランザクション中に更新したテーブルに対してのみオプティミスティックなチェックが実行されます。
Oracle データベースでは、CMP のキー以外のフィールドの型が java.util.Date
で実装型が Oracle DATE
であるエンティティ EJB で verify-columns
を Modified
に設定すると、キーではない DATE
フィールドに対して単純な更新が行われたときに、たとえ 1 人のユーザしかレコードを更新していなくても WebLogic Server が Optimistic 同時方式の違反例外を送出します。
この問題は、Oracle DATE
カラムと java.util.Date
型の日付値の制度が異なるために発生します。java.util.Date
型はミリ秒単位ですが、Oracle DATE
カラムは違います。このエラーは、以下の 2 通りの方法で防止できます。
Timestamp
(Oracle9i で導入されたより精度の高い型) に設定する。java.util.Date
値のミリ秒を削除するロジックをアプリケーションに追加する。そのためには、次のようにしてエンティティ Bean の java.util.Date
フィールドに合わせて日付フィールドを準備します。 Bean が読み込み専用であることを示すために使用します。コンテナは、複数のリクエストが並行して処理されるように各トランザクションで新しい Bean インスタンスをアクティブ化します。 WebLogic Server は、read-timeout-seconds パラメータに基づいて読み込み専用 Bean の ejbLoad()
を呼び出します。
WebLogic Server 8.1 SP02 より前のバージョンでは、ReadOnly を使用する EJB で作成および削除操作が許可されていました。WebLogic Server 8.1 SP02 では、ReadOnly を使用する EJB で作成と削除は許可されていません。その理由は、このプラクティスが推奨されていないことと、読み込み専用 Bean でもっと効率的なコードを生成できるようにするためです。
SP02 以前の動作をサポートし、読み込み専用 Bean が作成および削除操作を使用できるようにするには、weblogic-cmp-jar.xml
で allow-readonly-create-and-remove 要素を設定します。
同時方式は、パフォーマンスとデータの鮮度の間でトレードオフを生じさせます。アプリケーションでどの要素がより重要であるかに基づいて、同時方式を選択してください。トレードオフについては、表 6-5 を参照してください。
|
|
|
|
|
|||
|
|
||
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
要素のコンフィグレーションEJB 2.0 を実行する場合は、Optimistic 同時方式を使用する単一 Bean で read-mostly パターンを模倣することができます。オプティミスティックな Bean は、読み込みを実行するときに読み込み専用 Bean のように機能します (キャッシュから読み込み、古いデータを返すことがある)。ただし、オプティミスティックな Bean が書き込みを実行するときは、コンテナによって更新対象のデータが変更されていないようにします (Database 同時方式を使用する Bean と同じレベルの書き込みの一貫性が提供される)。「同時方式の選択」を参照してください。
weblogic-ejb-jar.xml
の entity-descriptor
スタンザの invalidation-target 要素は、CMP エンティティ Bean が修正されたときに無効化すべき読み込み専用エンティティ EJB を特定します。
invalidation-target
は、EJB 2.0 CMP エンティティ Bean でのみ指定できます。対象の ejb-name は、読み込み専用エンティティ EJB でなければなりません。
read-only エンティティ Bean を無効にするには、CachingHome
または CachingLocalHome
インタフェースの次の invalidate()
メソッドを呼び出します。
コード リスト 6-10CachingHome インタフェースと 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
で明示的に指定しない場合に予想される動作という観点で関連要素が定義されています。
表 6-6 weblogic-cmp-jar.xml のコンテナ管理による関係要素
|
|
|
|