3.18 連続問合せ通知のサポート
Oracle Data Provider for .NETでは、Continuous Query Notificationをサポートする通知フレームワークが提供され、問合せ結果セット、スキーマ・オブジェクトまたはデータベースの状態に変更があったときに、Oracle Data Provider for .NETデータベース接続が存在していなくても、アプリケーションがクライアント側の通知を受け取れます。Continuous Query Notificationを使用すると、アプリケーションでは、クライアント側のキャッシュ妥当性(ADO.NET DataSet
など)を簡単に維持できます。連続問合せ通知は以前、データベース変更通知と呼ばれていました。
注意:
連続問合せ通知は、.NETストアド・プロシージャではサポートされません。
通知フレームワークを使用して、アプリケーションではデータベースの通知要求に対する登録済問合せとして問合せ結果セットを指定し、この通知登録を作成して問合せ結果セットの妥当性を維持できます。クライアント側のキャッシュの問合せ結果に影響するデータベースに変更があれば、通知フレームワークがアプリケーションに通知します。
注意:
変更通知の内容は無効化メッセージとして参照されます。これは、問合せ結果セットが現在無効であり、変更についての情報を提供していることを示します。
無効化メッセージにより提供される情報に基づき、アプリケーションはそれに応じた動作ができます。たとえば、アプリケーション内のローカルに格納されている、登録済問合せのデータのコピーをリフレッシュする必要がある場合があります。
注意:
登録済オブジェクトがデータベースから削除され、同じ名前の新規オブジェクトが同じスキーマ内に作成される場合、再登録して新規作成されたオブジェクトの通知を受け取る必要があります。
関連項目:
WindowsファイアウォールなどのファイアウォールでTCPネットワーク・ポートをブロックする設定になっていると、データベースからの通知を受信できません。ファイアウォールの構成を確認して、データベース・アプリケーションが連続問合せ通知のポートを使用できるようにしてください。
Oracle Database 11gおよびODP.NET 11g(11.1)以降、連続問合せ通知の問合せは、問合せベース(デフォルト)またはオブジェクトベースになります。問合せベースの登録では、選択した行がデータベースで変更されるとODP.NETからアプリケーションへ通知されます。オブジェクトベースの登録の場合は、選択した行を含む表に変更が生じるとODP.NETからアプリケーションへ通知されます。
問合せベースの登録には、保証モードとベストエフォート・モードの2つのモードがあります。保証モードでは、連続問合せ通知によって、問合せ結果セットに含まれている内容に変更があったことが保証されます。ただし、複雑な問合せは、保証モードで登録できません。このような場合は、ベストエフォート・モードが使用されます。
ベストエフォート・モードでは、問合せベースの登録の問合せが簡略化されます。簡略化が原因で通知が失われることはありません。ただし、簡略バージョンの結果は元の問合せの結果が変更されなくても変更される場合があるため、簡略化によって誤検出が発生することがあります。ベストエフォート・モードの問合せベースの登録を問合せに含める場合は、いくつかの制限があります。このような場合、開発者はほとんどの問合せタイプを登録できるオブジェクトベースの登録を使用できます。オブジェクトベースの登録では、問合せオブジェクトが変更されると、実際の問合せ結果に変更がなくても通知が生成されます。このことは、オブジェクト・ベースの登録が、問合せベースの登録よりも誤検出することが多いということも意味します。開発者は、各連続問合せ通知オプションの相対的な長所と短所を認識し、要件に最も適したものを選択する必要があります。
多くの行を一度に変更する場合、相当量の共有プール・リソースを消費するため、アプリケーションは変更された特定行の情報を持つ変更通知を受け取りません。かわりに、OracleNotificationEventArgs.Info
プロパティをOracleNotificationInfo.Error
に設定した通知を受け取ります。
この項には次のトピックが含まれます:
関連項目:
-
Windowsファイアウォールの設定の詳細は、『Oracle Databaseプラットフォーム・ガイドfor Microsoft Windows』を参照
-
連続問合せ通知の詳細は、『Oracle Database開発ガイド』を参照
3.18.1 連続問合せ通知のクラス
次のクラスは連続問合せ通知サポートに関連しています。
-
OracleDependency
アプリケーションとそれに関連するデータベース・イベントに基づいたOracle Database間の依存性を表します。これには依存性に関する情報が含まれており、指定のデータベース・イベントが発生した際にアプリケーションに通知する方法が提供されます。また
OracleDependency
クラスでは、データベース通知をリスニングする通知リスナーも作成されます。各アプリケーション・ドメインには、データベース通知リスナーが1つのみあります。アプリケーション・プロセスが終了すると、この通知リスナーも終了します。アプリケーションとデータベースの間の依存性は、
OracleDependency
オブジェクトの作成時には確立されません。依存性は、このOracleDependency
オブジェクトに関連付けられたコマンドの実行時に確立されます。そのコマンドの実行により、データベース内に連続問合せ通知の登録が作成されます。データベース内で変更が発生すると、
OracleDependency
オブジェクトのHasChanges
プロパティがtrueに設定されます。さらに、イベント・ハンドラがOracleDependency
オブジェクトのOnChange
イベントで登録された場合、登録済イベント・ハンドラ関数が起動されます。 -
OracleNotificationRequest
データベース内に登録される通知要求を表します。これには、要求に関する情報と通知のプロパティが含まれます。
-
OracleNotificationEventArgs
指定されたデータベース・イベントが発生し、そのデータベース・イベントに関する詳細が含まれる際に通知に対して生成された、無効化メッセージを表します。
3.18.2 サポートされている操作
ODP.NET通知フレームワークでは、連続問合せ通知と連携して次のアクティビティがサポートされます。
-
通知登録の作成
-
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文で使用すると、連続問合せ通知のコールバックに渡されるOracleNotificationEventArgs
オブジェクトにROWID
が戻されません。
-
-
リスナー・ポート番号の定義
デフォルトでは、静的な
OracleDependency.Port
プロパティは-1
に設定されています。これは、ODP.NETがアプリケーション実行時に初めて連続問合せ通知の要求を登録した場合、ランダムに選択されたポート上でODP.NETがリスニングすることを示します。ODP.NETは、1つのポート上でリスニングするリスナーをアプリケーション・ドメイン内に1つのみ作成します。ODP.NETでリスナーが起動されると、ポート番号を変更できません。リスナーがすでに作成されている場合、静的な
OracleDependency.Port
プロパティに対する変更はエラーになります。
3.18.3 通知登録の要件
接続済ユーザーは、通知登録を作成する、CHANGE
NOTIFICATION
権限を持っている必要があります。
このSQL文により、CHANGE
NOTIFICATION
権限が付与されます。
grant change notification to user name
このSQL文により、CHANGE
NOTIFICATION
権限が取り消されます。
revoke change notification from user name
3.18.4 連続問合せ通知の使用
この項では、アプリケーションで実行する必要がある処理、およびアプリケーションが連続問合せ通知を使用して登録済問合せ結果セットから変更結果の通知を受け取る際の処理フローを説明します。
3.18.4.1 アプリケーション側の手順
アプリケーションで必要になる手順は次のとおりです。
-
OracleDependency
インスタンスを作成します。 -
データベースの変更が検出されたときにアプリケーションでイベント・ハンドラを起動する場合は、イベント・ハンドラを
OracleDependency.OnChange
イベント・プロパティに割り当てます。それ以外の場合は、OracleDependency
オブジェクトのHasChanges
プロパティに対してポーリングするよう、アプリケーションで選択できます。このイベント・ハンドラは、変更通知を受け取ると起動されます。 -
リスナーがリスニングを行うポート番号を設定します。アプリケーションでは、1つの通知リスナーがリスニングを行うポート番号を指定できます。アプリケーションでポート番号を指定しないと、ランダムな番号がリスナーで使用されます。
-
実際に実行される問合せを含む
OracleCommand
インスタンスにOracleDependency
インスタンスをバインドします。内部的に、連続問合せ通知要求(OracleNotificationRequest
インスタンス)が作成され、OracleCommand.Notification
プロパティに割り当てられます。
3.18.4.2 通知処理フロー
-
通知要求に関連付けられたコマンドが実行されると、データベース内に通知登録が作成されます。コマンドの実行により、結果セットが戻される、または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 continuous query 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; } } }
3.18.5 ベスト・プラクティスの指針とパフォーマンス上の考慮点
この項では、連続問合せ通知およびODP.NET通知フレームワークの使用上、役立つ指針を提供し、パフォーマンスへの影響について説明します。変更通知登録が行われると、データベース・メモリー、ストレージまたはネットワーク・リソース(あるいはそれらの組合せ)が消費されます。リソースの消費量は、さらに、無効化メッセージのボリュームとサイズに依存します。多数の中間層クライアントに適切に対応するために、クライアントで次のベスト・プラクティスを実装することをお薦めします。
-
表の数を減らし、多くを読取り専用にすること
登録済のオブジェクト数を減らし、多くを読取り専用にしてください。オブジェクトの揮発性がきわめて高い場合、多数の無効化通知が送信され、大量のスペース(メモリー内またはディスク上)が必要になる可能性があります。これは、オブジェクトが多数登録されている場合にも当てはまります。
-
各表で更新される行の数を減らすこと
トランザクションでは、登録済の表中の行のうち、少数のみを更新(または挿入、削除)するようにしてください。任意の表で、単一のトランザクション内で更新する行が多すぎると、データベース・リソースに応じて、表全体が無効化される可能性があります。
この方針により、単一の無効化メッセージのサイズが抑制され、無効化キュー用のディスク・ストレージが削減されます。
関連項目:
連続問合せ通知の詳細は、Oracle Database開発者ガイドを参照