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通知フレームワークの使用上、役立つ指針を提供し、パフォーマンスの影響について説明します。変更通知登録が行われると、データベース・メモリー、ストレージまたはネットワーク・リソース(あるいはそれらの組合せ)が消費されます。リソースの消費量は、さらに、無効化メッセージのボリュームとサイズに依存します。多数の中間層クライアントに適切に対応するために、クライアントで次のベスト・プラクティスを実装することをお薦めします。
表の数を減らし、多くを読取り専用にすること
登録済のオブジェクト数を減らし、多くを読取り専用にしてください。また無効化の頻度を下げてください。オブジェクトの揮発性がきわめて高い場合、多数の無効化通知が送信され、大量のスペース(メモリー内またはディスク上)が必要になる可能性があります。これは、オブジェクトが多数登録されている場合にも当てはまります。
各表で更新される行の数を減らすこと
トランザクションでは、登録済の表中の行のうち、少数のみを更新(または挿入、削除)するようにしてください。任意の表で、単一のトランザクション内で更新する行が多すぎると、データベース・リソースに応じて、表全体が無効化される可能性があります。
この方針により、単一の無効化メッセージのサイズが抑制され、無効化キュー用のディスク・ストレージが削減されます。