Oracle® Fusion Middleware Oracle Application Development FrameworkによるFusion Webアプリケーションの開発 12c (12.2.1.2.0) E82918-03 |
|
![]() 前 |
![]() 次 |
この章の内容は次のとおりです。
状態管理は、同じまたは異なるページに対する複数のリクエストで状態およびページ情報を維持するためのプロセスです。
現実世界のほとんどのビジネス・アプリケーションでは、マルチステップのユーザー・タスクをサポートする必要があります。トランザクションWebサイトは、ステップ・バイ・ステップ・スタイルのユーザー・インタフェースを使用し、論理的な順序のページを通してエンド・ユーザーをタスクの完了まで導きます。タスクが終了すると、ユーザーは全体をまとめて保存またはキャンセルできます。ただし、HTTPプロトコルは、個別でステートレスなリクエストの概念に基づいて構築されるため、ユーザー・アクションの順序を論理的でステートフルな作業ユニットにグループ化する作業はアプリケーション開発者が行うことになります。
HTTPプロトコルの制限事項のため、制約がなく、すべての列の型が文字ベースとして定義されているデータベース表のシャドウ・セットを利用する解決策が開発者によって発明されました。このような解決策の使用は、短期間に非常に複雑になります。最終的に、より汎用的で実現可能な方法でこのような問題に対処するには、なんらかの種類の汎用アプリケーション状態管理機能が必要になります。ADFビジネス・コンポーネントは、このソリューションをすぐに実装できる状態で提供します。
状態管理を利用すると、メモリー、信頼性または実装の複雑さの問題に陥ることなく、マルチステップのユースケースをサポートするWebアプリケーションを簡単に作成できます。Oracle ADFでは、アプリケーション・モジュール・プールを使用してセッション状態を実装および管理するプロセスが簡略化されています。これらのプールは、アプリケーション・モジュール・キャッシュを安全に解放する構成可能なリソース・マネージャです。デフォルトでは、ADFビジネス・コンポーネント・プロジェクトにより、アプリケーション内のアプリケーション・モジュール定義ごとに1つのアプリケーション・モジュール・プールが有効になります。
Fusion Webアプリケーションでは、次のレベルで状態管理が提供されます。
タスク・フローに実装されたADFコントローラ・レイヤーの後で使用するための保存の機能(「タスク・フローでのセーブポイントの使用」を参照)。
「保存」は、ADFコントローラ・レイヤーでアクティブ化され、現在のUIおよびコントローラの状態のスナップショットを自動的に保存し、さらにADFモデル・レイヤーに委譲することでその状態も保存します。後で使用するための保存では、未完了のトランザクションが検証規則の強制またはデータの送信なしで保存されます。これを使用して、データおよびリージョン、ビュー・ポート、ポートレットに関する状態情報を保存できます。明示的保存(ユーザーが開始)または暗黙的保存(ユーザーによる操作なし)のどちらにも対応するセーブ・ポイントに関連付けられているアプリケーション状態とデータを後からリストアできます。エンド・ユーザーは、もともとはアプリケーションの終了時に保存されたデータと同じものを使用して、同じトランザクションの処理を再開できます。
ADFモデル・レイヤーのアプリケーション状態管理機能は、アプリケーション・モジュールで実装されます。
アプリケーション状態管理機能によって、ADFランタイムは、各ユーザー・セッションのアプリケーション状態を自動的に管理して、スケーラビリティの高いアプリケーションをサポートします。アプリケーション・モジュールは、保留中トランザクション状態のXMLドキュメントへの受動化(格納)をサポートし、XMLドキュメントは、インメモリーまたはデータベースの単一の汎用的な表に、一意の受動化スナップショットIDをキーとして格納されます。また、これらの保存されているXMLスナップショットの1つから保留中トランザクション状態を能動化する逆の操作もサポートします。この受動化およびアクティブ化は、アプリケーション・モジュール・プールによって必要に応じて自動的に実行され、指定できる構成プロパティによって制御されます。「受動化とアクティブ化が行われるタイミングの管理」で説明しているように、この重要な機能を最大限に活用するには、背後で行われていることを理解しておく必要があります。
アプリケーション状態管理は、サーバー・ファーム、またはフェイルオーバーを使用するクラスタ化サーバー環境に対応します。
フェイルオーバーが有効な複数アプリケーション・サーバー環境でデプロイする場合、以降のエンドユーザー・リクエストは、サーバー・ファームまたはクラスタ内の任意のサーバーで処理できます。このシナリオに対応するために、アプリケーション状態管理機能は、すべてのリクエストの最後にアプリケーション・モジュールを受動化します。フェイルオーバーが発生してユーザー・セッションが別のサーバー・ノードにリダイレクトされた場合、セッションCookieでは、データベース利用のXMLスナップショットから、保留中のアプリケーション状態を再アクティブ化でき、このとき、どのサーバーがこの要求を処理するかは関係ありません。アプリケーション・モジュールの受動化およびアクティブ化にはクラスタ・フェイルオーバーのサポートが組み込まれており、追加の構成は必要ありません。フェイルオーバーのADFサポートの詳細は、「Fusion Webアプリケーションの高可用性の構成」を参照してください。
ADFビジネス・コンポーネントのアプリケーション・モジュールを使用して、完全にステートレスなアプリケーションを実装したり、複数のブラウザ・ページが関係する作業単位をサポートしたりできます。図56-1は、これらのマルチステップ・シナリオをサポートするための状態管理機能の基本アーキテクチャを示しています。
図56-1 ADFが提供するデータベースを利用した汎用的な状態管理
ADFバインディング・コンテキストは、エンド・ユーザーごとのHttpSession
に存在する1つのオブジェクトです。このコンテキストが保持するのは、軽量アプリケーション・モジュール・データ・コントロール・オブジェクトへの参照であり、このオブジェクトは、各リクエスト時(データ・コントロールにアクセスしたとき)におけるプールからのアプリケーション・モジュール・インスタンスの取得と、各リクエストの終了時のプールへの解放を管理します。データ・コントロールは、ユーザー・セッションを識別するアプリケーション・モジュール・ハンドルへの参照を保持します。具体的には、保留中トランザクションで作成または変更されるアプリケーション・モジュール状態のシリアル化セッション・オブジェクトは、この手法を使用するHttpSession
には保存されません。これにより、ユーザーごとに必要なセッション・メモリーが最小になり、サーバーがクラスタ構成の場合のセッション・レプリケーションに関係するネットワーク・トラフィックがなくなります。
一般的な検索後に編集を行うシナリオでは、エンド・ユーザーは、更新する適切な行を検索して発見した後、作業を保存するかキャンセルするかを決定する前に、関連するマスター/ディテール情報の複数のページを開いて編集を行うことができます。エンド・ユーザーが休暇の予約をオンラインで行う別のシナリオを考えてみます。プロセスには、エンド・ユーザーによる次の詳細情報の入力が含まれる場合があります。
旅行に含まれる1つ以上の飛行機利用区間
旅行する1人以上の乗客
座席の選択と食事の指定
異なる都市での1つ以上のホテルの部屋
借りる自動車
ユーザーは途中で、トランザクションの完了、後で行うための予約の保存、または保存前のトランザクションの中止を決定します。
これらのシナリオには複数のWebページにまたがる論理的な作業単位が含まれることは明らかです。これまでの章では、JDeveloperのJSFページ・ナビゲーション・ダイアグラムを使用してこのようなユースケースに対するページ・フローを設計する方法を見てきましたが、それはパズルのほんの一部にすぎません。途中のビジネス・ドメイン・オブジェクト(Trip
、Flight
、Passenger
、Seat
、HotelRoom
、Auto
など)に対してエンド・ユーザーが行う保留変更は、各エンド・ユーザーに対するアプリケーションの進行中状態を表します。これとともに、前のステップで行われた選択に関する他の種類の記録された情報が、アプリケーション状態の全体像を構成します。
マルチステップ・アプリケーション・シナリオを容易に想像できる場合もありますが、Webアプリケーションでの実装は、HTTP (hypertext transfer protocol)のステートレスな性質のために複雑になります。図56-2は、サイトへのエンド・ユーザーの訪問がHTTPの一連のリクエスト/レスポンスのペアで構成される様子を示しています。しかし、HTTPには、Webサーバーが異なるユーザーのリクエストを区別したり、同じユーザーがサイトとの対話中に行った異なるリクエストを区別したりするための手段がありません。サーバーは、ユーザーからのリクエストを、常にそれが最初にして唯一のものであるかのように受け取ります。
図56-2 Webアプリケーションが使用するステートレスなHTTPプロトコル
図56-3で示されているように、ステートレスなHTTPプロトコルを介した同じエンド・ユーザーからのリクエスト・シーケンスの継続を認識するために使用される手法には、cookieと呼ばれる一意の識別子が関係します。Cookieは名前と値のペアであり、サイトに対してユーザーが行う各HTTPリクエストのヘッダー情報で送信されます。ユーザーが行う最初のリクエストには、Cookieは含まれていません。サーバーは、cookieが存在しないことを利用して、ユーザーとサイトとの対話セッションの開始を検出し、そのユーザーに対するそのセッションを表す一意の識別子をブラウザに返します。実際のCookieの値は文字と数字から成る長い文字列ですが、説明を簡単にするために、一意の識別子はサイトを使用する異なるユーザーに対応するAやZなどの1文字であるものとします。
Webブラウザは、サーバーから返されるCookieを認識するための標準的な方法をサポートすることによって、次の項目を識別することが可能になっています。
Cookieを送信したサイト
Cookie値を保持する必要のある期間
そのユーザーがそれ以降に行う各リクエストにおいて、ブラウザは、Cookieの有効期限が切れるまで、リクエストのヘッダーとともにCookieを送信します。サーバーは、Cookieの値を使用して、異なるユーザーによって行われたリクエストを区別します。
Cookieは、最初に作成されてから週、月または年が経過してから有効期限が切れるように単一のブラウザ・セッションを超えて持続するように設定できますが、セッションCookieは、ユーザーがブラウザを閉じると有効期限が切れます。
図56-3 セッションCookieとサーバー・サイド・セッションを使用した状態の追跡
Java EEに準拠するWebサーバーが提供するHttpSession
と呼ばれる標準のサーバー・サイド機能を利用すると、Webアプリケーションで、特定のユーザーのセッションに関連するJavaオブジェクトを、属性と値の名前付きのペアとして保管できます。あるリクエストでこのセッションMap
に格納されたオブジェクトは、同じセッションの以降のリクエストが処理されている間に、アプリケーションが取得できます。
<web.xml>
ファイルの<session-timeout>
要素によって指定される時間枠内で、ユーザーが新しいリクエストの送信を続けている間、セッションはアクティブ状態を保ちます。デフォルトのセッションの長さは、通常は30分前後で、コンテナによって異なります。
HttpSession
機能はほとんどのアプリケーション状態管理戦略の構成要素ですが、使用方法を誤ると、パフォーマンスと信頼性の問題につながる可能性があります。まず、アプリケーションが作成するセッション・スコープのJavaオブジェクトはJava EE Webサーバーのメモリーに保持されるため、サーバーで障害が発生すると、HTTPセッションのオブジェクトは失われます。
図56-4で示されているように、信頼性を高める1つの方法は、複数のJava EEサーバーをクラスタ構成にすることです。このようにすると、Java EEアプリケーション・サーバーはユーザーごとのHTTPセッションのオブジェクトをクラスタ内の複数のサーバーにレプリケートするため、1台のサーバーが停止しても、オブジェクトはクラスタ内の他のサーバーのメモリーに存在し、ユーザーのリクエストの処理を続行できます。クラスタは異なるサーバーで構成されるため、サーバー間でのHTTPセッション・コンテンツのレプリケーションには、HTTPセッション・オブジェクトに対して行われた変更の、ネットワークを通したブロードキャストが含まれます。
図56-4 サーバー・クラスタでのセッション・レプリケーション
HTTPセッションの乱用は、パフォーマンスに影響を与える可能性があります。
アクティブなユーザーが増えると、サーバーで作成されるHTTPセッションが増加します。
HTTPセッションごとに格納されるオブジェクトが増えると、必要なメモリーが増加します。ユーザーがアクティブでなくなってもメモリーが解放されない点に注意してください。これが発生するのは、セッション・タイムアウトまたは明示的なセッション無効化の場合のみです。ユーザーが常にログアウトするわけではないため、セッション無効化は常に発生するとはかぎりません。
クラスタにおいて、各HTTPセッションで変化するオブジェクト増えると、変化したオブジェクトをクラスタの他のサーバーにレプリケートするために生成されるネットワーク・トラフィックが増加します。
最初は、セッションで保管されるオブジェクトの数を最小限に保つことで問題に対処できるように思われます。しかし、これは、各ユーザーの保留中のアプリケーション状態を一時的に格納するために代替メカニズムを利用することを意味します。ADFビジネス・コンポーネントは、このソリューションをすぐに実装できる状態で提供します。
受動化とアクティブ化は、アプリケーション・プールが処理できるよりも多くのオンライン・ユーザーがいる場合にリクエスト間で一時ユーザー・データを保持するように設計されています。
受動化/アクティブ化サイクルは、アプリケーション・モジュール・プーリングに対応しており、本来は妥当な数のキャッシュをメモリーに維持することを目的として設計されましたが、高可用性のクラスタ化サーバー環境でのフェイルオーバーにも対応しています。ただし、このプロセスでは、データベースへのアプリケーション・モジュール状態の読み書きが必要であり、それ自体が費用のかかる操作になります。32ビット・プラットフォームで構成されるレガシー・システムでは、通常、今日の中間層サーバーよりも利用可能なメモリー量は少なく、アプリケーション・モジュール・インスタンスの受動化によってメモリー制限が補正されていました。
今日のシステムでは、一般的にRAMが制限事項ではなくなり、中間層サーバーのメモリー使用量を減らすことで受動化/アクティブ化から得られるメリットはわずかになっています。現在は、クラスタ化サーバー環境での障害状況に対応することが、アプリケーション・モジュール・プーリングに組み込まれた受動化/アクティブ化サイクルの最適な利用手段になっています。
次のシナリオは、アプリケーション・モジュール状態の自動的な受動化とアクティブ化が行われるタイミングを表しています。このバックグラウンドは、受動化/アクティブ化の使用を制限するためにアプリケーション・モジュール・プーリングをどのようにチューニングするかを後で理解する場合に役立ちます。
HTTPリクエストの開始時に、アプリケーション・モジュール・データ・コントロールは、プールからアプリケーション・モジュール・インスタンスをチェックアウトすることで、beginrequest
イベントを処理します。
アプリケーション・モジュール・プールは、参照されないインスタンスを返します。参照されないアプリケーション・モジュールとは、その時点では他のユーザー・セッションに対する保留中の状態を管理していないモジュールです。
リクエストの終了時に、アプリケーション・モジュール・データ・コントロールは、アプリケーション・モジュール・インスタンスを管理対象状態モードでプールに戻すことで、endrequest
イベントを処理します。
アプリケーション・モジュール・インスタンスは、この時点では、それを使用していたデータ・コントロールによって参照されています。また、アプリケーション・モジュール・インスタンスは、データ・コントロールによって行われ、メモリーに格納された、保留中のトランザクション状態(つまり、エンティティ・オブジェクトおよびビュー・オブジェクトのキャッシュ、行われてまだコミットされていない変更、およびカーソル状態)をまだ含んでいるオブジェクトです。この後で説明するように、インスタンスは、このデータ・コントロールに専用のものではなく、参照されているのみです。
以降のリクエストでは、そのアプリケーション・モジュール・ハンドルによって識別される同じデータ・コントロールが、アプリケーション・モジュール・インスタンスを再びチェックアウトします。
プールが使用するユーザー・アフィニティによるステートレスなアルゴリズムのため、状態がまだメモリー内に存在しているまったく同じアプリケーション・モジュール・インスタンスがプールから返されます。
アプリケーション・モジュール・プーリングのデフォルト構成により、サイトに同時にアクセスするユーザー数が多いピーク使用時は、異なるユーザー・セッションでアプリケーション・モジュール・インスタンスを順番に再利用する必要があることが指示されます。この場合、アプリケーション・プールは、現在参照されているアプリケーション・モジュール・インスタンスを別のセッションによる使用のために次のようにリサイクルします。
ユーザーAのセッションのアプリケーション・モジュール・データ・コントロールは、リクエストの終了時に、アプリケーション・モジュール・インスタンスをアプリケーション・プールにチェックインします。このインスタンスの名前をAM1
とします。
ユーザーZの新しいセッションのアプリケーション・モジュール・データ・コントロールは、初めてプールにアプリケーション・モジュール・インスタンスを要求しますが、使用可能な参照されていないインスタンスはありません。このとき、アプリケーション・モジュール・プールは次のようにします。
インスタンスAM1
の状態をデータベースに受動化します。
別のセッションが使用するための準備として、AM1
の状態をリセットします。
AM1
インスタンスをユーザーZのデータ・コントロールに返します。
その後のリクエストで、ユーザーAのセッションのアプリケーション・モジュール・データ・コントロールが、プールにアプリケーション・モジュール・インスタンスを要求します。このとき、アプリケーション・モジュール・プールは次のようにします。
参照されていないインスタンスを取得します。
これは、前述の手順2と同じタスクに従って取得されたインスタンスAM1
である場合も、または途中で参照されなくなった場合は別のインスタンスAM2
である場合もあります。
ユーザーAに対する適切な保留中状態をデータベースから能動化します。
アプリケーション・モジュール・インスタンスをユーザーAのデータ・コントロールに返します。
つまり、受動化、アクティブ化およびリサイクルのプロセスにより、データ・コントロールごとに専用のアプリケーション・モジュール・インスタンスを必要とせずに、データ・コントロールによって参照される状態をリクエスト間で保持します。前述のシナリオのブラウザ・ユーザーはどちらも、複数のHTTPリクエストにわたってアプリケーション・トランザクションを継続しますが、エンド・ユーザーには、バックグラウンドで受動化と能動化が行われているかどうかはわかりません。保留中の変更が継続して表示されるだけです。エンド・ユーザーが作業の論理的な単位をコミットできる状態になるまで、保留中の変更を基礎のアプリケーション・データベースの表に保存する必要はありません。アプリケーション・モジュール・プールは、アプリケーション・モジュール・インスタンスを、その保留中状態を管理している現在のデータ・コントロールにできるかぎり結び付けておこうとします。これは、ユーザー・セッション・アフィニティの維持と呼ばれます。
最適なパフォーマンスを実現するには、デプロイしたFusion Webアプリケーションでの受動化/アクティブ化サイクルの必要性を最小限に抑えます。これを制御するにはデフォルトの構成パラメータを変更します。これらのパラメータでは、アプリケーション・モジュール・プールのサイズを指定して、プール・マネージャのリソース・クリーンアップ動作を制御し、ユーザー・リクエストの最後にアプリケーション・モジュール・インスタンスで使用されるJDBC接続の切断動作をチューニングします。アプリケーション・モジュール・プールを調整して受動化を軽減する設計時構成パラメータの詳細は、「アプリケーション・モジュール・プーリング構成パラメータに関する必知事項」を参照してください。
Webアプリケーションのデフォルト・モードであるオプティミスティック・ロックを使用することをお薦めします。ペシミスティック・ロックは、行レベル・ロックの形でデータベースに保留トランザクション状態を作り出すため、Webアプリケーションでは使用しないようにする必要があります。ペシミスティック・ロックを設定しても状態管理は動作しますが、ロック・モードは予想したほどのパフォーマンスになりません。裏側では、アプリケーション・モジュールがリサイクルされるたびに、JDBC接続でロールバックが発行されます。これにより、ペシミスティック・ロックが作成していたすべてのロックが解放されます。
パフォーマンスに関するヒント:
常に、Webアプリケーションのデフォルト・モードであるオプティミスティック・ロックを使用します。オプティミスティック・ロックのみが、アプリケーション・モジュールの非管理解放レベル・モードと互換性があり、この場合、Webページが終了すると、アプリケーション・モジュール・インスタンスをすぐに解放することができます。これにより、多くのユーザーがアプリケーションに同時にアクセスすることが見込まれるWebアプリケーションで、最高レベルのパフォーマンスが実現されます。
構成がオプティミスティック・ロックを使用していることを確認するには、adf-config.xml
概要エディタの「ビジネス・コンポーネント」ページを開き、「ロック・モード」(jbo.locking.mode
プロパティに対応)がoptimistic
またはoptupdate
になっていることを確認します。adf-config.xml
エディタを開くには、「アプリケーション・リソース」ウィンドウで、「ディスクリプタ」および「ADF META-INF」フォルダを展開し、ファイル・ノードをダブルクリックします。
オプティミスティック・ロック(optimistic
)では、SELECT FOR UPDATE
文を発行して行をロックし、更新識別子属性を比較することによって、行が別のユーザーによって変更されているかどうかを判定します。また、更新識別子が指定されていない場合は、エンティティ・オブジェクトがキャッシュにフェッチされたときに存在していた、現在のエンティティのすべての永続的な属性の値を比較します。
オプティミスティック・ロック(optupdate
)では、ロックは実行されません。UPDATE
文が、現在のエンティティ・オブジェクトがフェッチされた時から属性値が変わっていない場合にかぎり既存の行と一致するWHERE
句を含むことによって、行が別のユーザーによって更新されたかどうかを判定します。
ADFの状態管理メカニズムは、受動化と能動化を利用して、アプリケーション・モジュール・インスタンスの状態を管理します。この機能の安定した実装は、すべての保留中の変更が中間層のアプリケーション・モジュール・トランザクションによって管理される場合にのみ可能です。最もスケーラブルな戦略は、保留中の変更を中間層のオブジェクトに維持し、HTTPリクエストの間で保留データベース状態が存在するような操作を実行しないようにすることです。これにより、アプリケーション・モジュール・プールが提供するパフォーマンスの最適化を最大限に利用し、アプリケーションにとって最も安定したランタイム動作を実現できます。
注意:
jbo.doconnectionpooling
構成パラメータをtrue
に設定する場合(一般に、データベース接続の共通プールを複数のアプリケーション・モジュール・プールで共有するため)、アプリケーション・モジュールをアプリケーション・モジュール・プールに解放すると、そのJDBC接続が解放されてデータベース接続プールに戻され、その接続でROLLBACK
が発行されます。その結果、ポストされていてコミットされていなかったすべての変更が失われます。次のリクエストで、アプリケーション・モジュールが使用されると、プールからJDBC接続を受け取りますが、前回使用していたものとは異なるJDBC接続インスタンスである可能性があります。これにより、データベースにポストされ、前のリクエストの間にコミットされていなかった変更は、失われます。
jbo.doconnectionpooling
構成パラメータは、アプリケーション・モジュール構成(bc4j.xcfg
ファイル)の概要エディタの「データベースとスケーラビリティ」タブで、「解放時にアプリケーション・モジュールの切断」プロパティを選択して設定します。
検証前の変更をコミットせず、トランザクションから強制的に送信するようなトランザクション・レベルのpostChanges()
メソッドが存在します。このメソッドは、同一のHTTPリクエスト内でのトランザクションのコミットまたはロールバックが必ず実行される場合を除き、Webアプリケーションでの使用はお薦めしません。使用した場合、複数の異なるクライアントにより、アプリケーション・モジュールとデータベース接続の両方がプールされ、シリアルに共有されるという事態が環境内で発生する可能性があります。
なんらかの理由で、postChanges()
メソッドを呼び出して、またはPL/SQLのストアド・プロシージャをコールして、特定のリクエスト内でデータベースにトランザクション状態を作成する必要があり、同じリクエストの終わりまでにコミットまたはロールバックを発行できない場合は、後のリクエストでコミットまたはロールバックするまでの間に、そのリクエストから予約レベルでアプリケーション・モジュール・インスタンスを解放する必要があります。
注意:
データベースでのトランザクション状態の作成から最後のコミットまたはロールバックの実行までを可能なかぎり短くして使用します。これは、予約レベルがアプリケーションのスケーラビリティと信頼性に悪影響を及ぼすため、予約レベルを長時間使用する必要がないようにします。
アプリケーション・モジュールを予約レベルで解放すると、予約レベルを明示的に管理レベルまたは非管理レベルに変更して戻すまで、以降のすべてのリクエストは予約レベルのままになります。したがって、コミットまたはロールバックを発行したら、責任を持って予約レベルを管理レベルに戻す必要があります。
開発プロセス中に、アプリケーション・モジュールをアクティブ化しても安全であることをテストすることが重要です。これは、アプリケーション・モジュール構成でアプリケーション・モジュール・プーリングを無効にすることで行います。
保留状態を受動化スナップショットから能動化したときにアプリケーション・モジュールが機能することを明確にテストしていない場合、システムに高い負荷がかかることによってシステムのこの面が初めてテストされたときに、本番環境で予期せず不愉快な経験をする可能性があります。
全体的なテスト計画の一部として、jbo.ampool.doampooling
構成パラメータをfalse
に設定した状態でアプリケーション・モジュールをテストする方法を採用することをお薦めします。このように設定すると、アプリケーション・モジュール・プーリングは完全に無効になり、ページ・リクエストがあるたびに、システムは受動化スナップショットからアプリケーション・モジュールの保留状態を能動化するように強制されます。これは、カスタム・アプリケーション・コードで行われている想定のために本番環境で発生する可能性のある問題を検出する優れた方法です。
注意:
テストが終了し、アプリケーションを本番環境でデプロイする準備が整ったら、アプリケーション・モジュールのプーリングを再度有効化することが重要です。構成プロパティjbo.ampool.doampooling
をfalse
に設定する構成は、本番環境のアプリケーションではサポートされていないため、アプリケーションをデプロイする前にtrue
に設定する必要があります。
たとえば、受動化されていると確信している一時ビュー・オブジェクト属性がある場合、この手法を使用すると、意図したとおりに動作しているかどうかをテストできます。さらに、次のものを導入している状況を考えてみます。
アプリケーション・モジュール、ビュー・オブジェクトまたはエンティティ・オブジェクトのプライベート・メンバー・フィールド
Session
ユーザー・データ・ハッシュ表のカスタム・ユーザー・セッション状態
カスタム・コードでは、このカスタム状態がHTTPリクエスト間で維持されているものとされている場合があります。JDeveloper Integrated WebLogic Serverを使用して1人のユーザーでテストしている場合、または少数のユーザーでテストしている場合は、問題なく動いているように見えます。これは、ADFアプリケーション・モジュール・プールのアフィニティによるステートレスの最適化によるものです。システムの負荷が許せば、プールは後のリクエストでもユーザーに同じアプリケーション・モジュール・インスタンスを返し続けます。しかし、負荷が大きい、現実の使用においては、この最適化を実現できない場合があり、使用できる任意のアプリケーション・モジュール・インスタンスを取得して、受動化スナップショットから保留状態を再能動化することが必要になります。カスタム・コンポーネントの状態を受動化スナップショットに保存してそこからリロードするためのpassivateState()
とactivateState()
のオーバーライド(「受動化時のカスタム・ユーザー固有情報の管理」を参照)が正しく行われていないと、この再能動化ステップの後でカスタム状態が失われます(つまり、null
になるか、デフォルト値に戻ります)。jbo.ampool.doampooling
をfalseに設定してテストすることで、コードに存在するこの種の状況を素早く検出できます。
ビジネス・コンポーネント構成プロパティを構成する方法の詳細は、「構成プロパティの宣言的設定方法」。
jbo.ampool.doampooling
構成プロパティは、アプリケーション・モジュール構成(bc4j.xcfg
ファイル)の概要エディタの「データベースとスケーラビリティ」タブにある「アプリケーション・モジュール・プーリングの有効化」オプションに対応しています。デフォルトでは、このチェック・ボックスは選択されていて、アプリケーション・モジュール・プーリングは有効になっています。本番環境でアプリケーションをデプロイする場合は、常にデフォルト設定のjbo.ampool.doampooling=true
にしてアプリケーションを実行します。ただし、テスト環境でアプリケーションを実行するかぎり、テストでは、このプロパティをfalse
に設定することで重要な役割を果せます。このプロパティがfalseの場合、実質的にアプリケーション・プールはありません。リクエストの最後でアプリケーション・モジュール・インスタンスが解放されると、ただちに削除されます。同じユーザー・セッションによって行われる以降のリクエストでは、リクエストを処理するために新しいアプリケーション・モジュール・インスタンスを作成する必要があり、アプリケーション・モジュールの保留状態を受動化ストアから再能動化する必要があります。
ビジネス・コンポーネント・プロパティを構成する方法の詳細は、「構成プロパティの宣言的設定方法」。
エンティティ・オブジェクトが複数のユーザーによって同時に更新され、これらのユーザーのいずれかが更新時にアプリケーション・モジュールのアフィニティを失った場合、エンティティ・オブジェクトに対して更新識別子が定義されていなければ、データを損失する可能性があります。
2人のユーザー(ユーザーAとユーザーB)が同じエンティティ・オブジェクトに同時にアクセスするシナリオについて考えてみましょう。
問合せの後、ユーザーBが属性の値を変更(たとえば、Dept
属性の値をAccounting
からResearch
に変更)して、コミットします。
その間に、ユーザーAも問合せを行い、Dept
属性の値がAccounting
になっている同じレコードを表示します。
ユーザーAは問合せに使用したアプリケーション・モジュールによるアフィニティを失い、受動化が発生します。
次にユーザーAがDept
属性の値をAccounting
からSales
に変更してコミットすると、アクティブ化が発生します。
アクティブ化が発生すると、Dept
属性の新しい値がアクティブ化されますが、ブラウザはデータ変更を認識せず、問題なくコミットが実行されます。
このタイプのシナリオを防止するには、すべてのエンティティ・オブジェクトに対して更新識別子属性を定義します。詳細は、「同時更新によるデータの消失を防ぐ方法」を参照してください。
アプリケーションがサブクラス化されたエンティティ・オブジェクトを使用する場合、新しいエンティティのキー属性を事前に移入する必要があります。キーを事前に移入しないと、受動化および能動化が失敗します。create()
メソッドをオーバーライドするかまたはコミット後に実際の値をデータベースからフェッチする前に一時的に負の値をキーに割り当てるDBSequence
タイプを使用することによってキー属性を事前に移入できます。詳細は、「トリガーによってデータベース順序から割り当てられた主キー値の取得方法」を参照してください。
アプリケーション・モジュール構成のオプションを構成して、受動化スナップショットを保存する場所を制御できます。データベース(デフォルト・オプション)、またはローカル・ファイル・システムに格納されたファイルに保存できます。
デフォルトでは、受動化スナップショットはデータベースに保存されますが、かわりにファイル・システムを使用するよう構成できます。
受動化されたXMLスナップショットは、データベースに保存される場合、jbo.server.internal_connection
プロパティで指定されている接続を使用して、PS_TXN
という名前の表のBLOB
列に書き込まれます。受動化レコードが保存されるたびに、受動化レコードには、PS_TXN_SEQ
順序から取得された順序番号に基づいて、一意の受動化スナップショットIDが割り当てられます。ADFバインディング・コンテキストのアプリケーション・モジュール・データ・コントロールによって保持されるアプリケーション・モジュール・ハンドルは、かわりに作成された最新の受動化スナップショットIDと、使用された前回のIDを記憶しています。
ADFランタイムは、PS_TXN
表およびPS_TXN_SEQ
順序の作成に使用する必要のあるデータベース接続およびスキーマを制御するjbo.server.internal_connection
という名前の構成プロパティを認識します。この構成パラメータの値が明示的に設定されていない場合、状態管理機能は、現在のアプリケーション・データベース接続の資格証明を使用して、一時的な表を作成します。
一時的な情報を別に保持するため、状態管理機能は、データベース接続プールから別の接続インスタンスを使用しますが、データベース資格証明は現在のユーザーと同じです。フレームワークは、一時的な表を作成し、存在しない場合には順序を作成することがあるため、jbo.server.internal_connection
の値を設定しないということは、現在のデータベース・ユーザーが、CREATE TABLE
、CREATE INDEX
およびCREATE SEQUENCE
の各権限を持つ必要があることを意味します。これは望ましくない場合が多いため、jbo.server.internal_connection
プロパティには常に適切な値を指定し、表とスキーマが作成される状態管理スキーマに対して資格証明を提供することをお薦めします。構成のjbo.server.internal_connection
プロパティに対する有効な値は、次のとおりです。
次のような、完全修飾されたJDBC接続URL:
jdbc:oracle:thin:
username
/
password
@
host
:
port
:
SID
次のような、JDBCデータ・ソース名:
java:/comp/env/jdbc/YourJavaEEDataSourceName
パフォーマンスに関するヒント:
PS_TXN
表を作成する際は、securefileを使用してLOBデータ(コンテンツ列)を格納し、PS_TXN
表に、グローバルでパーティション化された逆キー索引としてプライマリ列索引を作成します。LOBデータを処理する場合、securefile構成は、basicfile構成よりも優れたパフォーマンスをもたらします。逆キー索引は、挿入の比率が高い場合に発生する競合を削減することにより役立ちます。
受動化された情報は、複数の場所に格納できます。これを制御するには、アプリケーション・モジュール構成でオプションを構成します。選択肢は、データベースまたはローカル・ファイル・システムに格納されるファイルです。
ファイル
ファイルにアクセスする方がデータベースにアクセスするより速いため、これは使用できる最も速い選択肢である場合があります。中間層全体が同じマシン上にインストールされているか共有ファイル・システムにアクセスでき、受動化情報にアクセスできる場合には、この選択肢が適しています。通常、この選択肢は、使用されているOracle WebLogic Serverドメインが1つである小さい中間層に適しています。つまり、Oracle WebLogic Serverインスタンスが1つで、そのすべてのコンポーネントが1台の物理マシンにインストールされているような小型の中間層には、非常にふさわしい選択です。永続スナップショット・ファイルの場所と名前は、jbo.tmpdir
プロパティ(指定されている場合)によって決まります。この指定は、構成プロパティに関する通常のADFプロパティ優先順位の規則に従います。他になにも指定されていない場合、場所はuser.dir
によって決まります(指定されている場合)。これはデフォルトのプロパティであり、OS固有です。
データベース
これがデフォルトの選択です。ファイルへの受動化より少し遅くなる場合がありますが、信頼性ははるかに優れています。ファイルへの受動化でよくある問題は、リモートでインストールされているOracle WebLogic Serverインスタンスがアクセスできないことです。この場合、クラスタ環境では、1つのノードがダウンすると、他のノードは受動化された情報にアクセスできず、フェイルオーバーが機能しません。可能性のあるもう1つの問題は、リモート・ノードがファイルにアクセスできたとしても、ローカル・ノードとリモート・ノードでアクセス時間が大きく異なり、パフォーマンスが一定でなくなります。データベース・アクセスの場合、時間はすべてのノードでほぼ同じです。
設計時に選択した値を設定するには、jbo.passivationstore
プロパティにdatabase
またはfile
を設定します。値null
は、接続の種類に固有のデフォルトを使用することを示します。OracleまたはDB2の場合はデータベースによる受動化を使用し、それ以外はファイル・シリアライズを使用します。
アプリケーション・モデルの受動化によって保存される情報は、トランザクション状態と非トランザクション状態の2つの部分に分かれます。トランザクション状態は、エンティティ・オブジェクト・データに対して行われた、データベースへの保存が意図されている更新のセットであり、エンティティ・オブジェクトに対して直接実行されるか、ビュー・オブジェクトの行を介してエンティティに実行されます。非トランザクション状態は、現在の行インデックス、WHERE
句、ORDER BY
句など、ビュー・オブジェクトの実行時設定で構成されます。
アプリケーション・モジュールの受動化スナップショットの一部として保存される情報には、次のものが含まれます。
このユーザー・セッションに対するルート・アプリケーション・モジュールのエンティティ・キャッシュにおける新しいエンティティ、変更されたエンティティおよび削除されたエンティティ(変更の場合は新旧の値を含みます)。
アクティブ・ビュー・オブジェクトごとに次のもの(静的および動的に作成されたもの両方):
各行セットの現在の行インジケータ(通常は1)
新しい行とその位置。(新しい行は、更新された行とは別に扱われます。ビュー・オブジェクトにおけるそのインデックスも追跡されます。)
ViewCriteriaおよびビュー基準行などの関連するすべてのパラメータ。
行セットが実行されたかどうかを示すフラグ
範囲の開始と範囲のサイズ
アクセス・モード
フェッチ・モードとフェッチ・サイズ
すべてのビュー・オブジェクト・レベルのカスタム・データ
注意:
設計時に受動化のためにビュー・オブジェクト一時属性が選択されている場合、その属性を保存できます。ただし、これにより、取得される行数が多くなると、スナップショットのサイズも大きくなっていくため、この機能は慎重に使用してください。一時属性の受動化を有効にする方法の詳細は、「ビュー・オブジェクトの状態の管理方法」を参照してください。
動的に作成された場合、またはビュー定義から変更された場合は、SELECT
、FROM
、WHERE
、ORDER BY
の各句
注意:
ADFビジネス・コンポーネントのランタイム診断を有効にしている場合は、各XML状態スナップショットの内容も保存されます。診断を有効にする方法の詳細は、「ADFビジネス・コンポーネント・デバッグ診断を有効化する方法」を参照してください。
ユーザー固有情報やインスタント変数など、ADFビジネス・コンポーネント・オブジェクト内のその他の情報は、受動化スナップショットの一部として保存されません。このタイプの情報を保存するには、「受動化時のカスタム・ユーザー固有情報の管理」で説明した手法を使用します。
JDeveloper内のadfbc_purge_statesnapshots.sql
スクリプトは、アプリケーション・モジュールの受動化スナップショット・レコードを時々クリーンアップするのに役立ちます。
通常の環境では、ADF状態管理機能は、受動化スナップショット・レコードを自動的にクリーンアップします。
JDeveloperでは、アプリケーション・モジュール状態管理表を定期的にクリーンアップするための手段として、adfbc_purge_statesnapshots.sql
スクリプトが提供されています。このファイルは、Oracle Middlewareインストール・ディレクトリのoracle_common
サブディレクトリにあります(例: ORACLE_HOME
\oracle_common\common\sql
)。
サーバーが開発時や障害時などに異常な方法でシャットダウンすると、永続的スナップショット・レコードが時間とともに蓄積します。SQL*Plusでスクリプトを実行すると、BC4J_CLEANUP
PL/SQLパッケージが作成されます。このパッケージには、2つの関連するプロシージャがあります。
PROCEDURE Session_State(olderThan DATE)
このプロシージャは、特定の日付より古いセッションのアプリケーション・モジュール・セッション状態記憶域をクリーンアップします。
PROCEDURE Session_State(olderThan_minutes INTEGER)
このプロシージャは、特定の分数より古いセッションのアプリケーション・モジュール・セッション状態記憶域をクリーンアップします。
このパッケージの適切なプロシージャの呼出しをデータベース・ジョブとして発行することで、ADFの一時的永続記憶域の定期的なクリーンアップをスケジュールできます。
次の例に示すような匿名PL/SQLブロックを使用することで、bc4j_cleanup.session_state()
の実行を、翌日の2:00amに開始してそれ以降毎日実行し、状態が1日(1440分)を超えているセッションをクリーンアップするようスケジュールできます。
SET SERVEROUTPUT ON DECLARE jobId BINARY_INTEGER; firstRun DATE; BEGIN -- Start the job tomorrow at 2am firstRun := TO_DATE(TO_CHAR(SYSDATE+1,'DD-MON-YYYY')||' 02:00', 'DD-MON-YYYY HH24:MI'); -- Submit the job, indicating it should repeat once a day dbms_job.submit(job => jobId, -- Run the ADF Purge Script for Session State -- to cleanup sessions older than 1 day (1440 minutes) what => 'bc4j_cleanup.session_state(1440);', next_date => firstRun, -- When completed, automatically reschedule -- for 1 day later interval => 'SYSDATE + 1' ); dbms_output.put_line('Successfully submitted job. Job Id is '||jobId); END; . /
セッションCookieのかわりに受動化レコードがデータベースに保存されたとき、この受動化レコードにより、新しい一意のスナップショットIDが取得されます。同じトランザクションの一部として、その同じセッションCookieによって使用されていた前のスナップショットIDを持つ受動化レコードは削除されます。これにより、サーバー障害がなければ、受動化スナップショット・レコードはアクティブなエンド・ユーザー・セッションごとに1つのみ存在します。
セッションCookieに関係する受動化スナップショット・レコードは、アプリケーション・モジュールが非管理状態レベルでプールにチェックインされると削除されます。これは次の場合に発生します。
コードがアプリケーション・モジュール・データ・コントロールでresetState()
を明示的に呼び出す場合
たとえば明示的なログアウト機能の実装の一部などとして、コードがHttpSession
を明示的に無効化する場合
アイドル時間に対するセッション・タイムアウトのしきい値を超え、フェイルオーバー・モードが無効(デフォルト)になっているため、HttpSession
がタイムアウトする場合
いずれの場合も、アプリケーション・モジュール・プールは、セッションCookieによって参照されていたアプリケーション・モジュールも参照されていない状態にリセットします。基礎となるデータベース表には変更が保存されていないため、保留中のセッション状態スナップショットが削除されると、その時点までにユーザー・セッションが完了した未終了作業のトレースは残りません。
フェイルオーバー・モードが有効になっていると、セッションが非アクティブなためにHttpSession
がタイムアウトした場合、ユーザーがブラウザに戻ったときに作業を再開できるよう、受動化スナップショットが維持されます。
アクションが中断された後、エンド・ユーザーがブラウザに戻ってアプリケーションの使用を続けると、なにも変化がなかったかのように作業は継続されます。セッションCookieは、リクエストを処理する前のユーザーの最新の保留中状態スナップショットで、使用可能なアプリケーション・モジュール・インスタンスを再能動化するために使用されます。これにより、ユーザーの次のリクエストが新しいHttpSession
のコンテキストで処理されても(別のアプリケーション・サーバー・インスタンスであっても)、ユーザーはこのことに気付きません。
注意:
アプリケーション・モジュールが予約レベルで解放された場合、HttpSession
はタイムアウトし、ユーザーは認証プロセスを実行する必要があり、保存されていない変更はすべて失われます。
web.xml
ファイル内の<session-timeout>
タグを使用して、ユーザーが離席しているか非アクティブのときにHTTPセッションが解放されるようにタイムアウトしきい値を構成できます。
HTTPはステートレス・プロトコルであるため、クライアントがブラウザを閉じたり週末で不在になったことの暗黙の通知を、サーバーが受け取ることはありません。このため、Java EEに準拠するサーバーは、ユーザーがリクエスを停止したときにHTTPセッションに結び付けられているリソースを解放できるよう、標準的で構成可能なセッション・タイムアウトのメカニズムを提供します。プログラムでタイムアウトを強制することもできます。
web.xml
ファイルの<session-timeout>
タグを使用して、セッションのタイムアウトのしきい値を構成できます。デフォルト値は通常は30分前後で、コンテナによって異なります。
セッション・タイムアウトの期限が切れる前にユーザーのセッションを終了するには、ユーザーがログアウトのボタンやリンクをクリックした際に、バッキングBeanからHttpSession
オブジェクトのinvalidate()
メソッドを呼び出します。これにより、セッションがタイムアウトした場合と同じ方法でHttpSession
がクリーンアップされます。JSFとADFを使用して、セッションを無効化した後は、単に転送を行うのではなく、表示する次のページへのリダイレクトを行う必要があります。次の例は、「ログアウト」ボタンからこのタスクを実行するサンプル・コードです。
public String logoutButton_action() throws IOException{ ExternalContext ectx = FacesContext.getCurrentInstance().getExternalContext(); HttpServletResponse response = (HttpServletResponse)ectx.getResponse(); HttpSession session = (HttpSession)ectx.getSession(false); session.invalidate(); response.sendRedirect("Welcome.jspx"); return null; }
暗黙のタイムアウトと同様に、HTTPセッションをこの方法でクリーンアップすると、参照されていたアプリケーション・モジュールは非参照としてマークされます。
ApplicationModuleImpl
クラスのpassivateState()
およびactivateState()
メソッドをオーバーライドすることで、カスタム・ユーザー定義情報をアプリケーション・モジュールに追加できます。
メンバー変数の形式、またはoracle.jbo.Session
ユーザー・データ・ハッシュ表に格納されるカスタム情報の形式で、カスタム・ユーザー定義情報をアプリケーション・モジュールに追加することは、ごく一般的な方法です。ADF状態管理機能では、ApplicationModuleImpl
クラス内のpassivateState()
メソッドおよびactivateState()
メソッドをオーバーライドすることで、このカスタム情報を受動化スナップショットにも保存するためのメカニズムが提供されています。
注意:
ViewObjectImpl
クラスとEntityObjectImpl
クラスでも、似たメソッドを使用して、これらのオブジェクトのカスタム状態を受動化スナップショットに保存できます。
passivateState()
およびactivateState()
をオーバーライドして、カスタム・アプリケーション・モジュール状態情報を受動化/能動化サイクルに確実に組み込むことができます。次に、これを行う方法を示します。
例にあるjbo.counter
には、アプリケーション・モジュール状態の受動化と能動化の過程で保持するカスタム値が含まれています。各アプリケーション・モジュールにはoracle.jbo.Session
というオブジェクトが関連付けられており、アプリケーション・モジュール固有のセッションレベル状態を格納します。セッションにはユーザー・データ・ハッシュ表があり、一時的な情報を格納できます。ユーザー固有のデータをアプリケーション・モジュールの受動化と能動化の過程で保持するには、このカスタム値をアプリケーション・モジュール状態の受動化スナップショットに保存してリストアするコードを記述する必要があります。
/** * Overridden framework method to passivate custom XML elements * into the pending state snapshot document */ public void passivateState(Document doc, Element parent) { // 1. Retrieve the value of the value to save int counterValue = getCounterValue(); // 2. Create an XML element to contain the value Node node = doc.createElement(COUNTER); // 3. Create an XML text node to represent the value Node cNode = doc.createTextNode(Integer.toString(counterValue)); // 4. Append the text node as a child of the element node.appendChild(cNode); // 5. Append the element to the parent element passed in parent.appendChild(node); } /** * Overridden framework method to activate custom XML elements * into the pending state snapshot document */ public void activateState(Element elem) { super.activateState(elem); if (elem != null) { // 1. Search the element for any <jbo.counter> elements NodeList nl = elem.getElementsByTagName(COUNTER); if (nl != null) { // 2. If any found, loop over the nodes found for (int i=0, length = nl.getLength(); i < length; i++) { // 3. Get first child node of the <jbo.counter> element Node child = nl.item(i).getFirstChild(); if (child != null) { // 4. Set the counter value to the activated value setCounterValue(new Integer(child.getNodeValue()).intValue()+1); break; } } } } } /* * Helper Methods */ private int getCounterValue() { String counterValue = (String)getSession().getUserData().get(COUNTER); return counterValue == null ? 0 : Integer.parseInt(counterValue); } private void setCounterValue(int i) { getSession().getUserData().put(COUNTER,Integer.toString(i)); } private static final String COUNTER = "jbo.counter";
「カスタム・ユーザー固有情報の受動化方法」の例に示すように、activateState()
をオーバーライドするときは、次の手順を実行します。
jbo.counter
要素の要素を検索します。
見つかった場合は、ノード・リストで見つかったノードをループします。
jbo.counter
要素の最初の子ノードを取得します。
これはDOM Textノードで、その値は前述のpassivateState()
メソッドが呼び出されたときに保存された、jbo.counter
属性の値を表す文字列です。
カウンタの値に、スナップショットから能動化された値を設定します。
passivateState()
がオーバーライドされると、次の手順で逆の処理を実行します。
保存する値を取得します。
値を収めるXML要素を作成します。
値を表すためのXMLテキスト・ノードを作成します。
テキスト・ノードを要素の子として追加します。
渡される親要素に要素を追加します。
注意:
XMLドキュメントでノードを操作するために使用するAPIは、org.w3c.dom
パッケージのDocument Object Model (DOM)インタフェースで提供されています。これらはJava API for XML Processing (JAXP)の一部です。詳細は、このパッケージに含まれるNode
、Element
、Text
、Document
、およびNodeList
の各インタフェースのJavadocを参照してください。
ビュー・オブジェクトを能動化した後で、能動化プロセスの最後に、activateState()
メソッドがコールされます。多くの場合、これは、アプリケーション・モジュール状態の能動化ロジックを配置する場所です。ただし、ADF状態管理機能がビュー・オブジェクトを能動化する前にアプリケーション・モジュールの能動化ロジックがカスタム状態情報を設定する必要がある場合(たとえば、実行時にビュー・オブジェクトがカスタム値を内部的に参照できるようにカスタム・コードを書き込む必要がある場合など)、ApplicationModuleImpl
クラスのprepareForActivation()
メソッドは能動化プロセスの最初に起動するため、これが正しい位置となります。
ビュー・オブジェクトは、デフォルトでは受動化済としてマークされます。ただし、一時的なビュー・オブジェクト(一時的な属性のみ含む)は、現在の行および他の非トランザクション状態に関連する更新のみを受動化します。
デフォルトでは、すべてのビュー・オブジェクトが受動化可能に設定されており、これによりそれらの状態が保存されます。ただし、一時属性を持つビュー・オブジェクトは、デフォルトではそれらの属性を受動化しません。ビュー・オブジェクトの概要エディタの「チューニング」ページを使用して、ビュー・オブジェクトの受動化方法、さらにどの属性が受動化されるかを変更できます。
ビュー・オブジェクトごとに、宣言的に受動化可能または不可能に構成できます。ビュー・オブジェクトが受動化可能ではない場合は、ビュー・オブジェクトに関する情報はアプリケーション・モジュールの受動化スナップショットに書き込まれません。
パフォーマンスに関するヒント:
UI上の値の表示に使用せず、値の計算または導出のための再入力可能メソッドでのみ使用される読取り専用ビュー・オブジェクトを受動化する必要はありません。これにより、受動化と能動化に関連するパフォーマンスのオーバーヘッドが取り除かれ、アプリケーション・モジュール・プールを維持するために必要なCPU使用率も減少します。
始める前に:
ビュー・オブジェクトの受動化に関する知識が役立つ場合があります。詳細は、「受動化時のビュー・オブジェクトの状態の管理」を参照してください。
ビュー・オブジェクトの受動化状態を設定するには:
能動化メカニズムは、ビュー・オブジェクトを、最後の受動化が発生したときの状態に戻すように設計されています。それを保証するために、Oracle ADFは、最後の問合せ実行で使用されたバインド変数の値を状態スナップショットに格納します。このバインド変数は、受動化時に行セットに設定された変数に追加されるものです。受動化状態も、ユーザーが適用したWHERE句を、受動化時の行セットに関連するビュー・オブジェクトに格納します。
一時ビュー・オブジェクト(一時属性のみを含むビュー・オブジェクト)は受動化可能に設定されていますが、ビュー・オブジェクトがデフォルトで受動化される設定になっているため、現在行およびその他の非トランザクション状態に関連する情報のみを受動化します。
パフォーマンスに関するヒント:
一時ビュー・オブジェクトの属性は、デフォルトでは受動化されません。その性質上、一時ビュー・オブジェクトの属性は読取り専用として意図されていることが普通であり、簡単に再作成できます。そのため、通常は、その値をXMLスナップショットの一部として受動化しても意味がありません。これにより、受動化と能動化に関連するパフォーマンスのオーバーヘッドが取り除かれ、アプリケーション・モジュール・プールを維持するために必要なCPU使用率も減少します。
始める前に:
ビュー・オブジェクトの受動化に関する知識が役立つ場合があります。詳細は、「受動化時のビュー・オブジェクトの状態の管理」を参照してください。
また、次のタスクを実行する必要があります。
JDeveloperでアプリケーションを開きます。
一時ビュー・オブジェクトの属性の受動化状態を個別に設定するには:
トランザクション機能はエンティティ・オブジェクト・レベルで管理されることが普通であるため、一時ビュー・オブジェクト属性の受動化はリソースやパフォーマンスの点で効率が低下します。一時ビュー・オブジェクトはエンティティ・オブジェクトに基づいていないため、すべての更新は、エンティティ・キャッシュではなく、ビュー・オブジェクト行キャッシュで管理されます。したがって、一時ビュー・オブジェクトまたは一時ビュー・オブジェクト属性を受動化するには、特別なランタイム処理が必要になります。
通常、受動化では変更された値のみを保存しますが、一時ビュー・オブジェクトの受動化では行全体を保存する必要があります。行には、受動化として設定されたビュー・オブジェクト属性のみが含まれます。
注意:
ADF受動化および能動化ロジックは、エンティティ・オブジェクトがポストされていない状態であるかぎりにおいてのみ、エンティティ・オブジェクトおよびビュー・オブジェクトの一時属性の回復を行います。ユーザーが変更をデータベースに保存すると、エンティティ・オブジェクトはデータベースにポストされ、次に能動化サイクルでデータベース・クエリを使用してビュー行が回復されます。属性は一時属性のため、その値はNULLのままです。エンティティ・オブジェクトまたはビュー・オブジェクトに基づく一時属性値がフェイルオーバー後も存続するようにするには、式を使用して一時属性を定義する必要があり、その式は値を指定できるgetterメソッドをポイントする必要があります。
受動化を使用すると、ビュー・オブジェクトを使用して、1つまたは複数のグローバル変数を、それぞれ別の一時属性に格納することができます。一時属性を受動化済としてマークすると、ADFビジネス・コンポーネント・フレームワークでは、高スループットとフェイルオーバーを実現するシナリオで受動化と能動化が発生しても、その一時的な値が保持されます。このため、低効率のHTTPセッション・レプリケーションでなく、状態管理メカニズムによりバックアップされるセッション・レベルのグローバル値を実装するほうが簡単です。また、必要に応じてUIのコントロールにバインドすることも簡単になります。
様々な画面の起動方法において、値を保存するには2つの基本的な方法があります。1つはコントローラ中心、もう1つはモデル中心の方法です。
コントローラ中心の方法を使用してADFコントローラ・レイヤーにこのタスクを実装すると、ページ・フロー・スコープの属性を使用した値の保存および参照が行われます。この方法は、いずれかのADFビジネス・コンポーネントの実装によってグローバル値を内部で参照する必要がない場合に適しています。ページ・フロー・スコープの詳細は、「タスク・フローのメモリー・スコープに関する必知事項」を参照してください。
モデル中心の方法では、概念的にはOracle Formsの非データベース・ブロックと等しい一時ビュー・オブジェクトが作成されます。
始める前に:
ビュー・オブジェクトの受動化に関する知識が役立つ場合があります。詳細は、「受動化時のビュー・オブジェクトの状態の管理」を参照してください。
また、次のタスクを実行する必要があります。
JDeveloperでアプリケーションを開きます。
「エンティティ・ベースのビュー・オブジェクトの作成方法」の説明に従い、ビュー・オブジェクト・ウィザードを使用して新規ビュー・オブジェクトを作成します。
ウィザードのページ1で、データソース: プログラム関連のオプションを選択します。
ページ2では、「新規」をクリックして一時属性名およびビューオブジェクトに含まれるタイプを定義します。
ページ3では、各属性の「更新可能」オプションを「常時」に設定します。
「終了」をクリックすると、概要エディタに新規作成されたビュー・オブジェクトが表示されます。
「既存のアプリケーション・モジュールへのマスター/ディテール・ビュー・オブジェクト・インスタンスの追加」に示すとおり、一時属性があるビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加します。
モデル中心の方法を使用してセッションレベルのグローバル変数を格納するには:
ビュー・オブジェクトでのエントリの実行を無効にします。
概要エディタの「一般」ページで、「チューニング」セクションを開きます。
「データベースから取得」グループで、行なしオプションを選択します。
ビュー・オブジェクトのデータがロールバック操作中にクリアされないよう注意してください。これを行うには、ビュー・オブジェクトのカスタムJavaクラスを有効にして、2つのロールバック・メソッドをオーバーライドします。
概要エディタで「Java」ナビゲーション・タブをクリックし、「Javaクラス」セクションの「編集」アイコンをクリックします。
「Javaオプションの選択」ダイアログで「ビュー・オブジェクト・クラスの生成」を選択して、「OK」をクリックします。
概要エディタで、「Javaクラス」セクションの「ビュー・オブジェクト・クラス」の隣のリンクをクリックします。
メイン・メニューから、「ソース」→「メソッドのオーバーライド」を選択します。
「メソッドのオーバーライド」ダイアログで、オーバーライドするbeforeRollback()
メソッドおよびafterRollback()
メソッドを選択し、次に「OK」をクリックします。
beforeRollback()
メソッドおよびafterRollback()
メソッドの両方で、Javaコードでsuper
のコールをコメント・アウトします。
新規ユーザーがアプリケーション・モジュールの使用を開始した場合は、ビュー・オブジェクトに空の行を作成します。
「アプリケーション」ウィンドウで、アプリケーション・モジュールをダブルクリックします。
「アプリケーション・モジュールのカスタム・クラスの生成方法」の説明に従って、アプリケーション・モジュールのJavaクラスを作成します(存在しない場合)。
「組込みフレームワーク・メソッドのオーバーライド方法」の説明に従って、アプリケーション・モジュールのprepareSession()
メソッドをオーバーライドします。
super.prepareSession()
をコールした後、新規行を一時ビュー・オブジェクトに作成するコードを追加し、これをビュー・オブジェクトに挿入します。
これで、「データ・コントロール」パネルを使用して、読取り専用要素および更新可能UI要素を、その他のビュー・オブジェクトと同様に、グローバルなビュー・オブジェクト属性にバインドできます。