Oracle Data Provider for .NETでは、Continuous Query Notificationをサポートする通知フレームワークが提供され、問合せの結果セット、スキーマ・オブジェクトまたはデータベースの状態に変更があったときにアプリケーションが通知を受け取れます。 Continuous Query Notificationを使用すると、アプリケーションでは、クライアント側のキャッシュ妥当性(ADO.NET DataSet
など)を簡単に維持できます。
注意: ODP.NET Database Change Notification機能は、Oracle DatabaseのContinuous Query Notification機能を使用します。 |
注意: Database Change Notificationは、.NETストアド・プロシージャではサポートされません。 |
データベースに関する通知要求に対する登録済問合せとして、アプリケーションで問合せ結果セットを指定し、この通知登録を作成すれば、通知フレームワークを使用して問合せ結果セットの妥当性を維持できます。 クライアント側のキャッシュの問合せ結果に影響を与える可能性のあるデータベースの変更があれば、通知フレームワークがアプリケーションに通知します。
注意: 変更通知の内容は無効化メッセージと呼ばれます。これは、問合せ結果セットが現在無効であり、変更についての情報を提供していることを示します。 |
無効化メッセージにより提供される情報に基づき、アプリケーションはそれに応じた動作ができます。たとえば、アプリケーション内のローカルに格納されている、登録済問合せのデータのコピーをリフレッシュする必要がある場合があります。
注意: 登録済オブジェクトがデータベースから削除され、同じ名前の新規オブジェクトが同じスキーマ内に作成される場合、再登録して新規作成されたオブジェクトの通知を受け取る必要があります。 |
デフォルトでは、Windows VistaおよびWindows XP Service Pack 2以上において、Windowsファイアウォールは、着信接続に対するほとんどすべてのTCPネットワーク・ポートをブロックできます。 したがって、これらのオペレーティング・システムでContinuous Query Notificationを適切に機能させるには、特定の実行可能ファイルで特定のポートをオープンできるように、Windowsファイアウォールを適切に設定する必要があります。
Oracle Database 11gおよびODP.NET 11g(11.1)以降では、問合せベース(デフォルト)またはオブジェクト・ベースのDatabase Change Notificationの問合せを使用できます。 問合せベースの登録では、選択した行がデータベースで変更されるとODP.NETがアプリケーションに通知します。 オブジェクト・ベースの登録では、選択した行を含む表に対するすべての変更をODP.NETがアプリケーションに通知します。
問合せベースの通知がサポートされるのは、次のすべての条件が満たされる場合のみです。
Oracle Databaseのバージョンが11.1以上であること。
VARCHAR2
およびNUMBER
以外の列データ型が選択リストに含まれていないこと。
データベースのCOMPATIBLE
初期化パラメータが11.0.0以上に設定されており、Automatic Undo Management(AUM)が使用可能(デフォルト)になっていること。
1の条件が満たされていない場合は、下位互換性のためにオブジェクト・ベースとして通知が登録されます。2の条件および記述されている他の制限が満たされていない場合は、ODP.NETでベスト・エフォート・モードが使用されるので、オブジェクト・ベースとして通知が登録されます。3の条件が満たされていない場合は、登録時にエラーが戻されます。問合せベースの変更通知の要件の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』のContinuous Query Notificationの使用に関する章を参照してください。
この項の内容は次のとおりです。
次のクラスは、Continuous Query Notificationサポートに関連付けられています。
OracleDependency
アプリケーションとそれに関連するデータベース・イベントに基づいたOracle Database間の依存性を表します。これには依存性に関する情報が含まれており、指定のデータベース・イベントが発生した際にアプリケーションに通知する方法が提供されます。またOracleDependency
クラスでは、データベース通知をリスニングする通知リスナーも作成されます。各アプリケーション・ドメインには、データベース通知リスナーが1つのみあります。アプリケーション・プロセスが終了すると、この通知リスナーも終了します。
アプリケーションとデータベースの間の依存性は、OracleDependency
オブジェクトの作成時には確立されません。依存性は、このOracleDependency
オブジェクトに関連付けられたコマンドの実行時に確立されます。そのコマンドの実行により、データベース内にデータベース変更通知登録が作成されます。
データベース内で変更が発生すると、OracleDependency
オブジェクトのHasChanges
プロパティがtrueに設定されます。さらに、イベント・ハンドラがOracleDependency
オブジェクトのOnChange
イベントで登録された場合、登録済イベント・ハンドラ関数が起動されます。
OracleNotificationRequest
データベース内に登録される通知要求を表します。これには、要求に関する情報と通知のプロパティが含まれます。
OracleNotificationEventArgs
指定されたデータベース・イベントが発生し、そのデータベース・イベントに関する詳細が含まれる際に通知に対して生成された、無効化メッセージを表します。
ODP.NET通知フレームワークでは、Continuous Query Notificationと連携して次のアクティビティがサポートされます。
通知登録の作成
OracleDependency
インスタンスを作成してOracleCommand
インスタンスにバインドします。
複数の通知要求を1つの登録にグループ化
OracleDependency.AddCommandDependency
メソッドを使用します。
同じOracleNotificationRequest
インスタンスを使用してOracleCommand.Notification
要求を設定します。
データベース変更通知の登録
OracleCommand
を実行します。通知プロパティがNULLであるか、NotificationAutoEnlist
がfalseである場合、通知は作成されません。
通知登録の削除
OracleDependency.RemoveRegistration
メソッドを使用します。
登録が作成される前に、OracleNotificationRequest
インスタンス内にTimeout
プロパティを設定します。
登録が作成される前に、OracleNotificationRequest
インスタンス内のIsNotifiedOnce
プロパティをtrue
に設定します。データベース通知が送信されると、登録が削除されます。
変更通知の永続性の確保
配信前に、無効化メッセージがデータベース内で永続的にキューされるかどうかを指定します。無効化メッセージがデータベース内で永続的に保存されると、変更通知の送信が保証されます。無効化メッセージをメモリー内キューに保存すると、変更通知はより素早く受信できますが、データベースのシャットダウンまたはクラッシュ時に失われる可能性があります。
次の項目を含む通知情報の取得:
変更されたオブジェクト名
変更されたオブジェクトのスキーマ名
通知を発生させるデータベース・イベント(挿入、削除など)
変更されたオブジェクト行のRowID
Oracle SQLでは、ROWIDTOCHAR(ROWID)
およびROWIDTONCHAR(ROWID)
関数により、ROWID
値がそれぞれVARCHAR2
およびNVARCHAR
データ型に変換されます。これらの関数がSQL文内で使用されている場合、ROWID
はデータベース変更通知コールバックに渡されるOracleNotificationEventArgs
オブジェクトには戻されません。
リスナー・ポート番号の定義
デフォルトでは、静的なOracleDependency.Port
プロパティは-1
に設定されています。これは、ODP.NETがアプリケーション実行時に初めてデータベース変更通知要求を登録した場合、ODP.NETがランダムに選択されたポート上でリスニングすることを示します。
ODP.NETは、1つのポート上でリスニングするリスナーをアプリケーション・ドメイン内に1つのみ作成します。ODP.NETでリスナーが起動されると、ポート番号を変更できません。静的なOracleDependency.Port
プロパティに対して変更を加えると、リスナーがすでに作成済である場合はエラーが発生します。
接続済ユーザーは、通知登録を作成する、CHANGE
NOTIFICATION
権限を持っている必要があります。
このSQL文により、CHANGE
NOTIFICATION
権限が付与されます。
grant change notification to user name
このSQL文により、CHANGE
NOTIFICATION
権限が取り消されます。
revoke change notification from user name
この項では、アプリケーションで実行する必要がある処理、およびアプリケーションがContinuous Query Notificationを使用して登録済問合せ結果セットから変更結果の通知を受け取る際の処理フローを説明します。
アプリケーションで必要になる手順は次のとおりです。
OracleDependency
インスタンスを作成します。
データベースの変更が検出されたときにアプリケーションでイベント・ハンドラを起動する場合は、イベント・ハンドラをOracleDependency.OnChange
イベント・プロパティに割り当てます。それ以外の場合は、OracleDependency
オブジェクトのHasChanges
プロパティに対してポーリングするよう、アプリケーションで選択できます。このイベント・ハンドラは、変更通知を受け取ると起動されます。
リスナーがリスニングを行うポート番号を設定します。アプリケーションでは、1つの通知リスナーがリスニングを行うポート番号を指定できます。アプリケーションでポート番号を指定しないと、ランダムな番号がリスナーで使用されます。
実際に実行される問合せを含むOracleCommand
インスタンスにOracleDependency
インスタンスをバインドします。 内部的に、Continuous Query Notification要求(OracleNotificationRequest
インスタンス)が作成され、OracleCommand.Notification
プロパティに割り当てられます。
通知要求に関連付けられたコマンドが実行されると、データベース内に通知登録が作成されます。コマンドの実行により、結果セットが戻される、またはPL/SQLストアド・プロシージャのREF
カーソルが1つ以上含まれる必要があります。
ODP.NETは、最初に成功した通知登録上でアプリケーション・リスナーを開始します。
データベース内で登録に関連する変更が発生すると、OracleDependency.OnChange
イベント・プロパティに割り当てられたイベント・デリゲート経由でアプリケーションに通知されるか、またはアプリケーションでOracleDependency.HasChanges
プロパティをポーリングできます。
次の例は、データベース変更通知機能を示しています。
// Database Setup // NOTE: unless the following SQL command is executed, // ORA-29972 will be obtained from running this sample /* grant change notification to scott; */ using System; using System.Threading; using System.Data; using Oracle.DataAccess.Client; using Oracle.DataAccess.Types; //This sample shows the database change notification feature in ODP.NET. //Application specifies to get a notification when emp table is updated. //When emp table is updated, the application will get a notification //through an event handler. namespace NotificationSample { public class MyNotificationSample { public static bool IsNotified = false; public static void Main(string[] args) { //To Run this sample, make sure that the change notification privilege //is granted to scott. string constr = "User Id=scott;Password=tiger;Data Source=oracle"; OracleConnection con = null; OracleDependency dep = null; try { con = new OracleConnection(constr); OracleCommand cmd = new OracleCommand("select * from emp", con); con.Open(); // Set the port number for the listener to listen for the notification // request OracleDependency.Port = 1005; // Create an OracleDependency instance and bind it to an OracleCommand // instance. // When an OracleDependency instance is bound to an OracleCommand // instance, an OracleNotificationRequest is created and is set in the // OracleCommand's Notification property. This indicates subsequent // execution of command will register the notification. // By default, the notification request is using the Database Change // Notification. dep = new OracleDependency(cmd); // Add the event handler to handle the notification. The // OnMyNotification method will be invoked when a notification message // is received from the database dep.OnChange += new OnChangeEventHandler(MyNotificationSample.OnMyNotificaton); // The notification registration is created and the query result sets // associated with the command can be invalidated when there is a // change. When the first notification registration occurs, the // notification listener is started and the listener port number // will be 1005. cmd.ExecuteNonQuery(); // Updating emp table so that a notification can be received when // the emp table is updated. // Start a transaction to update emp table OracleTransaction txn = con.BeginTransaction(); // Create a new command which will update emp table string updateCmdText = "update emp set sal = sal + 10 where empno = 7782"; OracleCommand updateCmd = new OracleCommand(updateCmdText, con); // Update the emp table updateCmd.ExecuteNonQuery(); //When the transaction is committed, a notification will be sent from //the database txn.Commit(); } catch (Exception e) { Console.WriteLine(e.Message); } con.Close(); // Loop while waiting for notification while(MyNotificationSample.IsNotified == false) { Thread.Sleep(100); } } public static void OnMyNotificaton(object src, OracleNotificationEventArgs arg) { Console.WriteLine("Notification Received"); DataTable changeDetails = arg.Details; Console.WriteLine("Data has changed in {0}", changeDetails.Rows[0]["ResourceName"]); MyNotificationSample.IsNotified = true; } } }
この項では、Continuous Query NotificationおよびODP.NET通知フレームワークの使用上、役立つ指針を提供し、パフォーマンスの影響について説明します。変更通知登録が行われると、データベース・メモリー、ストレージまたはネットワーク・リソース(あるいはそれらの組合せ)が消費されます。リソースの消費量は、さらに、無効化メッセージのボリュームとサイズに依存します。多数の中間層クライアントに適切に対応するために、クライアントで次のベスト・プラクティスを実装することをお薦めします。
表の数を減らし、多くを読取り専用にすること
登録済のオブジェクト数を減らし、多くを読取り専用にしてください。また無効化の頻度を下げてください。オブジェクトの揮発性がきわめて高い場合、多数の無効化通知が送信され、大量のスペース(メモリー内またはディスク上)が必要になる可能性があります。これは、オブジェクトが多数登録されている場合にも当てはまります。
各表で更新される行の数を減らすこと
トランザクションでは、登録済の表中の行のうち、少数のみを更新(または挿入、削除)するようにしてください。任意の表で、単一のトランザクション内で更新する行が多すぎると、データベース・リソースに応じて、表全体が無効化される可能性があります。
この方針により、単一の無効化メッセージのサイズが抑制され、無効化キュー用のディスク・ストレージが削減されます。