ヘッダーをスキップ
Oracle® TimesTen In-Memory Database Java開発者ガイド
11gリリース2 (11.2.2)
B66445-06
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

3 イベント管理のためのJMS/XLAの使用

TimesTen JMS/XLA APIを使用すると、ローカル・データベース内の特定の表への変更についてTimesTenを監視し、これらの変更の通知をリアルタイムで受信できます。JMS/XLAの主な目的は、トリガーの代替手段として、高性能かつ非同期の機能を提供することです。

JMS/XLAはJava Message Service(JMS)インタフェースを実装しているため、JavaアプリケーションでTimesTenトランザクション・ログAPI(XLA)機能を使用できます。JMSの情報およびリソースは、次の場所から利用可能です。

http://www.oracle.com/technetwork/java/jms/index.html

また、標準のJMS APIドキュメントは、TimesTenとともに次の場所にインストールされています。

install_dir/3rdparty/jms1.1/doc/api/index.html

TimesTen JMS/XLAアプリケーションをチューニングしてパフォーマンスを向上させる方法については、「JMS/XLAアプリケーションのチューニング」を参照してください。


注意:

『Oracle TimesTen In-Memory Database開発者および管理者ガイド』で説明されているTimesTenレプリケーション・ソリューションがニーズを満たさない場合、JMS/XLAを使用してカスタム・データ・レプリケーション・ソリューションを構築できます。

この章の内容は次のとおりです。

JMS/XLAの概念

Javaアプリケーションは、JMS/XLA APIを使用してTimesTenからイベント通知を受信できます。JMS/XLAは、JMSパブリッシュ・サブスクライブ・インタフェースを使用してXLA更新へのアクセスを提供します。

XLAへの接続を提供するJMS Sessionインスタンスを確立して永続サブスクライバ(TopicSubscriber)を作成し、更新をサブスクライブします。このサブスクライバを使用してメッセージを同時に受信および処理したり、リスナー(MessageListener)を実装して非同期に更新を処理できます。

JMS/XLAは、ローカル・データベースを監視するアプリケーション用に設計されています。TimesTenおよび通知を受信するアプリケーションは、同じシステム上に存在している必要があります。


注意:

JMS/XLA APIは、XLAのラッパーです。XLAによって更新レコードがトランザクション・ログ・バッファまたはトランザクション・ログ・ファイルから直接取得されるため、それらの更新レコードは読み取られるまで使用可能です。XLAを使用すると、複数のリーダーでトランザクション・ログの更新に同時にアクセスできます。

XLAの詳細は、『Oracle TimesTen In-Memory Database C開発者ガイド』のXLAおよびTimesTenのイベント管理に関する説明を参照してください。


この項の内容は次のとおりです。

XLAでレコードをトランザクション・ログから読み取る方法

アプリケーションによってデータベースが変更されると、TimesTenは、データへの変更およびトランザクション・コミットなどの他のイベントを示すトランザクション・ログ・レコードを生成します。

生成される新しいトランザクション・ログ・レコードは、常にトランザクション・ログ・バッファの最後に書き込まれます。トランザクション・ログ・レコードは、メモリ内のログ・バッファからディスク上のトランザクション・ログ・ファイルへ定期的に一括でフラッシュされます。

アプリケーションでは、XLAを使用してデータベースに対する変更のトランザクション・ログを監視できます。XLAは、トランザクション・ログ全体を読み取り、ログ・レコードをフィルタ処理し、目的の表および列への変更が含まれているトランザクション・レコードのリストをXLAアプリケーションに配信します。

XLAは、レコードをディスクリート・トランザクションにソートします。複数のアプリケーションが同時にデータベースを更新している場合、異なるアプリケーションのトランザクション・ログ・レコードがトランザクション・ログに交互配置されます。

XLAは、特定のトランザクションに関連するすべてのトランザクション・ログ・レコードを透過的に抽出し、それらを連続するリストにしてアプリケーションに配信します。

コミット済のトランザクションのレコードのみが返されます。コミット済のレコードは、最後のコミット・レコードがトランザクション・ログに書き込まれる順序で返されます。コミットされていないデータベースへの変更に関連するレコードは、XLAによってフィルタ処理されます。

変更が行われ、その後にロールバックされた場合、XLAは強制終了されたトランザクションのレコードをアプリケーションに配信しません。

XLAの基本的な概念の多くを示すトランザクション・ログの例を、次の図3-1および例3-1で検討してください。

図3-1 トランザクション・ログから抽出されるレコード

図3-1の説明が続きます。
「図3-1 トランザクション・ログから抽出したレコード」の説明

例3-1 トランザクション・ログ・レコードの読取り

この例では、トランザクション・ログに次のレコードが含まれています。


CT1: アプリケーションCは、表Wの行1を値7.7で更新。
BT1: アプリケーションBは、表Xの行3を値2で更新。
CT2: アプリケーションCは、表Wの行9を値5.6で更新。
BT2: アプリケーションBは、表Yの行2を値XYZで更新。
AT1: アプリケーションAは、表Zの行1を値3で更新。
AT2: アプリケーションAは、表Zの行3を値4で更新。
BT3: アプリケーションBがトランザクションをコミット。
AT3: アプリケーションAがトランザクションをロールバック。
CT3: アプリケーションCがトランザクションをコミット。

WYおよびZへの変更を検出するように設定されているXLAアプリケーションでは次のようになります。


BT2およびBT3: 表Yの行2を値XYZで更新し、コミット。
CT1: 表Wの行1を値7.7で更新。
CT2およびCT3: 表Wの行9を値5.6で更新し、コミット。

この例は、次のことを示します。

  • アプリケーションBおよびアプリケーションCのトランザクション・レコードがすべて書き込まれます。

  • トランザクション・ログでは、アプリケーションCのレコードがアプリケーションBのレコードより前に書き込まれますが、アプリケーションBのコミット(BT3)はアプリケーションCのコミット(CT3)より前に書き込まれます。その結果、アプリケーションBのレコードはアプリケーションCのレコードより先にXLAアプリケーションに返されます。

  • XLAは表Xへの変更を検出するように設定されていないため、アプリケーションBによる表Xへの更新(BT1)は示されません。

  • アプリケーションAによる表Zへの更新(AT1およびAT2)は、コミットされずにロールバックされたため(AT3)示されません。

XLAおよびマテリアライズド・ビュー

XLAを使用すると、表およびマテリアライズド・ビューの両方への変更を追跡できます。マテリアライズド・ビューによって、複数のディテール表内の選択した行および列への変更を追跡できる単一のソースが提供されます。マテリアライズド・ビューがない場合は、XLAアプリケーションで、すべてのディテール表の更新レコード(アプリケーションにとって重要ではない行および列への更新が反映されているレコードを含む)に対して監視およびフィルタ処理を行う必要があります。

通常、表に対する変更を追跡するためのXLAメカニズムと、マテリアライズド・ビューに対する変更を追跡するXLAメカニズムとの間に、処理上の違いはありません。ただし、非同期マテリアライズド・ビューの場合、非同期ビューに関するXLA通知の順序が、関連付けられているディテール表に関する順序、または同期ビューに関する順序と同じとはかぎらないことに注意してください。たとえば、ディテール表に対する挿入が2つある場合、非同期マテリアライズド・ビューでは、これらの2つが逆の順序で実行される可能性があります。また、更新が、削除に続く挿入としてXLAによって扱われることがあったり、複数の操作(複数の挿入や複数の削除)を組み合せて1つの操作にされることがあります。正確な順序に依存するアプリケーションでは、非同期のマテリアライズド・ビューを使用しないでください。

マテリアライズド・ビューの詳細は、次を参照してください。

  • 『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のCREATE MATERIALIZED VIEWに関する項

  • 『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のマテリアライズド・ビューの理解に関する項

XLAブックマーク

XLAブックマークは、トランザクション・ログ内のXLAサブスクライバ・アプリケーションの読取り位置にマークを付けます。ブックマークによって永続サブスクリプションが容易になり、アプリケーションはトピックから切断した後、読取りを中断した時点から、更新の受信を継続するために再接続できます。

この項の以降の内容は次のとおりです。

ブックマークの使用方法

XLAのメッセージ・コンシューマを作成する場合は、永続TopicSubscriberを使用します。サブスクライバを作成するときに指定するサブスクリプション識別子は、XLAブックマーク名として使用されます。表に対するXLAサブスクリプションを開始および停止するためにJDBCを介してttXlaSubscribeおよびttXlaUnsubscribe組込みプロシージャを使用する場合は、使用するブックマークの名前を明示的に指定します。

応答を受信すると、ブックマークは最終読取り位置にリセットされます。更新メッセージが確認される方法の詳細は、「XLA応答モード」を参照してください。

JMS Sessionオブジェクトでunsubscribe()をコールすることによって、永続サブスクリプションを削除できます。これにより、対応するXLAブックマークが削除され、再接続するときに新規のサブスクリプションが強制的に作成されます。詳細は、「ブックマークの削除」を参照してください。

使用中は、ブックマーク・サブスクリプションの変更はできません。サブスクリプションの変更には、メッセージ・コンシューマをクローズしてから、ttXlaSubscribeおよびttXlaUnsubscribeを使用してサブスクリプションを変更して、その後メッセージ・コンシューマをオープンする必要があります。


注意:

ttXlaBookmarkCreate TimesTen組込みプロシージャを使用して、ブックマークを作成することもできます。このファンクションの詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のttXlaBookmarkCreateに関する項を参照してください。

レプリケートされるブックマーク

アクティブ・スタンバイ・ペア・レプリケーション・スキームを使用している場合、jmsxla.xmlファイル(「JMS/XLA構成ファイルおよびトピック」を参照)内の<topic>要素のreplicatedBookmark属性に基づいたレプリケートされるブックマークを使用することができます。レプリケートされるブックマークでは、ブックマークへの操作が必要に応じてスタンバイ・データベースにレプリケートされるため、スタンバイに対する必要な書き込み権限があることを想定しています。これにより、フェイルオーバーが発生した場合、より効率的にブックマークの位置をリカバリできます。

レプリケートされたブックマークを使用する際には、次の順で手順を実行する必要があります。

  1. アクティブ・スタンバイ・ペアのレプリケーション・スキームを作成します。(これはcreate active standby pair操作、またはクラスタウェア管理環境のttCWAdmin -createコマンドによって行われます。)

  2. ブックマークを作成します。

  3. ブックマークをサブスクライブします。

  4. アクティブ・スタンバイ・ペアを起動します(このとき、スタンバイへの複製が発生し、レプリケーションが始まります)。(これはttRepAdmin -duplicateコマンド、またはクラスタウェア管理環境のttCWAdmin -startコマンドによって行われます。)


注意:

  • あるいは、ttXlaBookmarkCreateを使用してブックマークを作成する場合、このファンクションには、レプリケートされるブックマークを指定するためのパラメータがあります。

  • レプリケートされたブックマークをJMS/XLA構成ファイルで指定すると、アプリケーションの起動時にJMS/XLAがブックマークを作成し、ブックマークにサブスクライブします。(「JMS/XLA構成ファイルおよびXLAトピック」も参照してください。)


次の点に注意してください。

  • スタンバイ・データベースでのブックマークの位置は、アクティブ・データベースでのブックマークの位置に非常に近くなりますが、応答処理のレプリケーションは非同期に行われるため、応答処理の実行頻度によっては、フェイルオーバーの発生時に更新の重複を示す小さなウィンドウが表示されることがあります。

  • レプリケートされるブックマークが存在していても、アクティブ・スタンバイ・ペア・スキームは削除できます。ブックマークはその時点でレプリケートされなくなりますが、削除はされません。続けてアクティブ・スタンバイ・ペア・スキームを再度有効にすると、これらのブックマークは自動的にスキームに追加されます。

  • レプリケーション・エージェントが実行されている間は、レプリケートされるブックマークを削除できません。

  • アクティブ・データベースにあるレプリケートされるブックマークのみ、読み取りまたは応答が可能です。レプリケートされるブックマークに応答するたびに、その応答操作がスタンバイ・データベースに非同期にレプリケートされます。

XLAブックマークおよびトランザクション・ログの保持

XLAの使用時、XLAブックマークが進行するまで、TimesTenトランザクション・ログ・ファイルは保持されることを認識しておく必要があります。この保持により、XLAによって必要がないと判断されるまで、トランザクション・ログ・ファイルはパージされません。XLAアプリケーションが予期せず終了したり、そのブックマークの削除や変更トラッキングの無効化を行わずに切断した場合などに、ブックマークが固まってしまうと、ログは保持されたままになり、トランザクション・ログ・ファイルが過度に蓄積される場合があります。この蓄積により、ディスク領域が一杯になる場合があります。

この状況の監視および解決方法の詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のトランザクション・ログ・ファイルの蓄積の監視に関する説明を参照してください。

JMS/XLA構成ファイルおよびXLAトピック

XLAに接続するには、特定のデータベースに対応するJMS Topicオブジェクトへの接続を確立します。JMS/XLA構成ファイルでは、トピック名とデータベース間のマッピングが提供されます。

トピックを指定する際、<topic>要素にreplicatedBookmark="yes"と設定すると、レプリケートされるブックマークを指定できます。デフォルトの設定は"no"です。「XLAブックマーク」を参照してください。

デフォルトでは、JMS/XLAは、現在の作業ディレクトリでjmsxla.xmlという構成ファイルを検索します。そのファイルに別の名前または場所を使用する場合は、InitialContextクラスに環境変数の一部として指定し、その場所をクラスパスに追加する必要があります。

例3-2 JMS/XLA構成ファイルの指定

次のコードは、構成ファイルをInitialContextクラスの環境変数の一部として指定します。

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
  "com.timesten.dataserver.jmsxla.SimpleInitialContextFactory");
env.put(XlaConstants.CONFIG_FILE_NAME, "/newlocation.xml");
InitialContext ic = new InitialContext(env);

XlaConstants.CONFIG_FILE_NAMEが設定されている場合、JMS/XLA APIでは、クラス・ローダーを使用してJMS/XLA構成ファイルを検索します。この例では、JMS/XLA APIは、CLASSPATH環境変数で指定されている場所と、CLASSPATH変数で指定されているJARファイル内の最上位のディレクトリにあるnewlocation.xmlファイルを検索します。

また、JMS/XLA構成ファイルは、次のようにサブディレクトリに配置することもできます。

env.put(XlaConstants.CONFIG_FILE_NAME,
"/com/mycompany/myapplication/deepinside.xml");

この場合、JMS/XLA APIは、CLASSPATH環境変数で指定されている場所およびCLASSPATH変数で指定されているjarファイル内の両方のcom/mycompany/myapplicationサブディレクトリで、deepinside.xmlファイルを検索します。

JMS/XLA APIでは、最初に見つかった構成ファイルを使用します。

例3-3 構成ファイル内のトピックの定義

構成ファイル内のトピック定義は、名前、接続文字列、および1回で取得する更新数を指定するプリフェッチ値で構成されています。

たとえば、この構成では、DemoDataStoreトピックがTestDB DSNにマップされています。

<xlaconfig>
  <topics>
    <topic name="DemoDataStore"
      connectionString="DSN=TestDB"
      xlaPrefetch="100" />
  </topics>
</xlaconfig>

例3-4 レプリケートされるブックマークを使用するトピックの定義

レプリケートされるブックマークを使用するかどうかを、トピック定義で指定することもできます。レプリケートされるブックマークを前述の例に使用すると次のようになります。

<xlaconfig>
  <topics>
    <topic name="DemoDataStore"
      connectionString="DSN=TestDB"
      xlaPrefetch="100" replicatedBookmark="yes" />
  </topics>
</xlaconfig>

XLA更新

アプリケーションは、JMS MapMessageオブジェクトとしてXLA更新を受け取ります。MapMessageオブジェクトには、XLA更新ヘッダー内のフィールドに対応する一連の名前および値のペアが含まれています。

MapMessage取得メソッドを使用してメッセージ・フィールドにアクセスできます。getMapNames()メソッドは、メッセージ内のすべてのフィールドの名前を含むEnumerationオブジェクトを返します。メッセージの個々のフィールドを名前ごとに取得できます。予約されたすべてのフィールド名は、__TYPEのように2つのアンダースコアで始まります。

すべての更新メッセージには、メッセージに含まれている更新のタイプを示す__TYPEフィールドがあります。タイプは、整数値で指定されています。整数タイプと比較するために、com.timesten.dataserver.jmsxla.XlaConstantsに定義されている定数を使用します。表3-1に、サポートされているタイプを示します。

表3-1 XLA更新タイプ

更新タイプ 説明

INSERT

行が追加されました。

UPDATE

行が変更されました。

DELETE

行が削除されました。

COMMIT_ONLY

トランザクションがコミットされました。

CREATE_TABLE

表が作成されました。

DROP_TABLE

表が削除されました。

CREATE_INDEX

索引が作成されました。

DROP_INDEX

索引が削除されました。

ADD_COLUMNS

新規の列が表に追加されました。

DROP_COLUMNS

列が表から削除されました。

CREATE_VIEW

マテリアライズド・ビューが作成されました。

DROP_VIEW

マテリアライズド・ビューが削除されました。

CREATE_SEQ

順序が作成されました。

DROP_SEQ

順序が削除されました。

CREATE_SYNONYM

順序が作成されました。

DROP_SYNONYM

順序が削除されました。

TRUNCATE

表内のすべての行が削除されています。


XLA更新メッセージの内容の詳細は、「JMS/XLA MapMessageの内容」を参照してください。

XLA応答モード

XLAの応答のメカニズムでは、アプリケーションのメッセージの受信だけでなく、メッセージの正常な処理も確認するように設計されています。永続的に更新を応答すると、アプリケーションのXLAブックマークは、読み取られた最終レコードにリセットされます。これにより、以前に返されたレコードが再読み取りされないようになり、アプリケーションがXLAに再接続する場合にブックマークが再利用されるときに、アプリケーションがレコードの新しいバッチのみを受信するようになります。

JMS/XLAは、XLA更新メッセージに自動的に応答することも、応答するメッセージを明示的に選択することもできます。Sessionオブジェクトを作成したときに、更新の応答方法を指定します。

JMS/XLAでは、次の3つの応答方法がサポートされています。

  • AUTO_ACKNOWLEDGE: このモードでは、更新は受信時、自動的に応答されます。各メッセージは1回のみ配信されます。同じメッセージは繰り返し送信されないため、アプリケーションに障害が発生すると、メッセージが消失することがあります。メッセージは必ず個々に配信されて応答されるため、JMS/XLAでは複数のレコードをプリフェッチしません。トピック内のxlaprefetch属性は無視されます。

  • DUPS_OK_ACKNOWLEDGE: このモードでは、更新は自動的に応答されますが、アプリケーションに障害が発生すると、同じメッセージが繰り返し配信されることがあります。JMS/XLAはトピックに対して指定されているxlaprefetch属性に基づいてレコードをプリフェッチし、プリフェッチされたブロック内の最終レコードが読み取られると応答を送信します。プリフェッチされたすべてのレコードを読み取る前にアプリケーションに障害が発生すると、ブロック内のすべてのレコードは、アプリケーションの再起動時にアプリケーションに渡されます。

    xlaprefetchの設定例は、「JMS/XLA構成ファイルおよびトピック」を参照してください。

  • CLIENT_ACKNOWLEDGE: このモードでは、アプリケーションはMapMessageへのacknowledge()をコールすることによって更新メッセージの受信を確認します。JMS/XLAはトピックに指定されているxlaprefetch属性に基づいてレコードをプリフェッチします。

次の例では、応答モードを設定します。

Session session = connection.createSession (false, Session.CLIENT_ACKNOWLEDGE);

「更新確認の頻度の減少」も参照してください。

更新のプリフェッチ

複数の更新レコードを一度にプリフェッチする処理は、XLAから各更新レコードを個々に取得する処理より効率的です。AUTO_ACKNOWLEDGEモードを使用すると、更新がプリフェッチされないため、他のモードよりも時間がかかります。可能な場合は、更新を重複して行うことができるようにアプリケーションを設計すると、DUPS_OK_ACKNOWLEDGEの使用、または明示的な更新の確認が可能になります。各メッセージを個々に確認しないようにできるかぎり、通常は明示的な更新の確認によって、最高のパフォーマンスを得ることができます。

更新の確認

XLA更新に明示的に応答するには、更新メッセージでacknowledge()をコールします。メッセージを確認すると、暗黙的に以前のすべてのメッセージを確認します。通常は、確認と確認の間に、複数の更新メッセージを受信および処理します。CLIENT_ACKNOWLEDGEモードを使用していて、永続サブスクリプションを将来再利用する場合は、終了する前に、acknowledge()をコールして最後に読み取られた位置にブックマークを再設定する必要があります。

アクセス制御がXLAに与える影響

「アクセス制御のためのTimesTen機能の検討」では、TimesTenアクセス制御がデータベースの操作に与える影響の概要を提供しています。アクセス制御は、XLAに次のような影響を与えます。

  • XLA機能を実行するには、システム権限XLAが必要です。これには、TimesTenにXLAリーダーとして接続して(これにはCREATE SESSION権限も必要)、ttXlaBookmarkCreatettXlaBookmarkDeletettXlaSubscribeおよびttXlaUnsubscribe TimesTen XLA組込みプロシージャ(『Oracle TimesTen In-Memory Databaseリファレンス』の組込みプロシージャに関する説明を参照)を実行することも含まれます。

  • XLA 権限を持つユーザーは、SELECT ANY TABLESELECT ANY VIEWおよびSELECT ANY SEQUENCEのシステム権限と同等の操作を実行できます。

XLAの制限事項

TimesTenのJMS/XLAを使用する際は、XLAの次の制限事項に注意する必要があります。

  • JMS/XLAは、TimesTenでサポートされているすべてのプラットフォームで使用できます。ただし、異なるプラットフォーム間、または同じプラットフォームの32ビットと64ビットとの間でのデータの転送はXLAではサポートされていません。

  • LOBに対するJMS/XLAサポートは限定されています。詳細は、「表への更新の監視」を参照してください。

  • JMS/XLAでは、ドライバ・マネージャ・ライブラリまたはクライアント/サーバー・ライブラリにリンクされたアプリケーションはサポートされていません。

  • XLAリーダーは、インメモリー・コラム圧縮を使用する表はサブスクライブできません。

  • Oracle Databaseに対する変更トラッキング・トリガーでは、自動リフレッシュ・キャッシュ・グループの列レベルでの解決は行いません。(これは非常に高コストになります。)そのため、自動リフレッシュ機能は行のすべての列を更新し、実際にはすべての列のデータが変更されていない場合でも、XLAではすべての列が変更されたというレポートのみが行われます。

JMS/XLAとOracle GDKの依存性

JMS/XLA APIでは、DatabaseCharacterSet属性で指定されているデータベース・キャラクタ・セットからUTF-16エンコーディングに変換するために、Oracle Globalization Development Kit(GDK)の一部であるorai18n.jarを使用します。JMS/XLA APIは、TimesTenのリリースごとに固有のバージョンのGDKをサポートしています。JMS/XLAによって、JVMにロードされている以外のバージョンのGDKが検出されると、重大な警告が表示され、処理が続行されます。次のコマンドを入力すると、JMS/XLAでサポートされているGDKのバージョンを確認できます。

$ cd install_dir/lib
$ java -cp ./orai18n.jar oracle.i18n.util.GDKOracleMetaData -version

「Javaアプリケーションのコンパイル」も参照してください。

XLAへの接続

更新を受信するためにXLAに接続するには、接続を作成するためにJMS接続ファクトリを使用します。次に、この接続を使用してセッションを確立します。更新の処理を開始する準備ができたら、接続でstart()をコールしてメッセージの配信を有効にします。syncJMSクイック・スタート・デモから、次の例3-5でこれを示します。

例3-5 XLAへの接続

/* JMS connection */
private javax.jms.TopicConnection connection; 
/* JMS session */
private TopicSession session; 
...
// get Connection
Context messaging = new InitialContext(); 
TopicConnectionFactory connectionFactory =
        (TopicConnectionFactory)messaging.lookup("TopicConnectionFactory"); 
connection = connectionFactory.createTopicConnection(); 
connection.start(); 
...
// get Session
session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

表への更新の監視

更新の受信を開始する前に、変更の監視対象となる表をXLAに知らせる必要があります。

変更をサブスクライブして、表に対するXLAパブリッシングをオンにするには、JDBCを介してttXlaSubscribe組込みプロシージャをコールします。

ttXlaSubscribeを使用して表に対するXLAパブリッシングを有効にする場合は、次のように表を追跡するときに使用されるパラメータ(表の名前とブックマークの名前)を指定する必要があります。

ttXlaSubscribe(user.table, mybookmark)

たとえば、次のようにして、JDBC CallableStatementインタフェースでttXlaSubscribeをコールします。

Connection con;

CallableStatement cStmt;
...
cStmt = con.prepareCall("{call ttXlaSubscribe(user.table, mybookmark)}");
cStmt.execute();

停止時に、表からのサブスクライブを解除するには、ttXlaUnsubscribeを使用します。詳細は、「表からのサブスクライブ解除」を参照してください。

SYS.XLASUBSCRIPTIONSシステム表を確認することで、アプリケーションで表のサブスクリプションを検証できます。

JavaアプリケーションでTimesTen組込みプロシージャを使用する場合の詳細は、「プロシージャおよびファンクションを実行するためのCALLの使用」を参照してください。


注意:

JMS/XLAでのLOBのサポートは、次のとおり限定されています。
  • LOB列を含む表はサブスクライブできますが、LOB値自体の情報は入手できません。

  • LOBを含む列は空(長さがゼロ)またはnull(値が実際にNULLの場合)とレポートされます。この方法では、null列と非null列の違いがわかります。

その他の注意点については、次の「更新の受信および処理」の項を参照してください。


更新の受信および処理

XLA更新は、同期または非同期に受信できます。

トピックの更新を同期をとって受信および処理するには、次の手順を実行します。

  1. 永続TopicSubscriberインスタンスを作成してトピックをサブスクライブします。

  2. サブスクライバでreceive()またはreceiveNoWait()をコールして、次に使用可能な更新を取得します。

  3. 返されたMapMessageインスタンスを処理します。

トピックの更新を非同期に受信および処理するには、次の手順を実行します。

  1. 更新を処理するMessageListenerインスタンスを作成します。

  2. 永続TopicSubscriberインスタンスを作成してトピックをサブスクライブします。

  3. TopicSubscriberMessageListenerを登録します。

  4. 接続を開始します。


    注意:

    接続を開始する前にMessageListenerを登録しないと、メッセージを受信できない場合があります。接続済の場合は、接続を停止してMessageListenerを登録した後に、接続を再開します。

  5. メッセージを受信するまで待機します。アプリケーションがメイン・スレッド内で行う処理が他にない場合は、Objectメソッドwait()をコールしてメッセージを待機できます。

更新がパブリッシュされると、MessageListenerメソッドonMessage()がコールされ、メッセージがMapMessageインスタンスとして渡されます。

SYS.XLASUBSCRIPTIONSシステム表を確認することで、アプリケーションで表のサブスクリプションを検証できます。


注意:

XLAでのLOBのサポートは、限定されています。BLOBフィールドにはMapMessageメソッドのgetBytes()を使用し、CLOBまたはNCLOBフィールドにはgetString()を使用することによって更新メッセージでLOBフィールドにアクセスできますが、これらのフィールドには長さが0のデータが含まれる場合があります(または値が実際NULLの場合はnullデータが含まれます)。

例3-6(asyncJMSクイック・スタート・デモ)では、リスナーを使用して更新を非同期に処理します。

例3-6 リスナーを使用した更新の非同期処理

MyListener myListener = new MyListener(outStream);

outStream.println("Creating consumer for topic " + topic);
Topic xlaTopic = session.createTopic(topic);
bookmark = "bookmark";
TopicSubscriber subscriber = session.createDurableSubscriber(xlaTopic, bookmark);

// After setMessageListener() has been called, myListener's onMessage
// method is called for each message received.
subscriber.setMessageListener(myListener);

bookmarkは既に存在している必要があります。JDBCおよびttXlaBookmarkCreate組込みプロシージャを使用して、ブックマークを作成できます。また、TopicSubscriberは、永続サブスクライバである必要があります。XLA接続は永続的であるように設計されています。XLAブックマークによって、トピックからの切断が可能になり、更新が中断した位置から更新の受信を開始するために、再度接続することもできます。永続サブスクライバの作成時にサブスクリプション識別子として渡す文字列は、XLAブックマーク名として使用されます。

JMS TopicSessionunsubscribe()をコールして、アプリケーションの停止時にそのサブスクライバが使用したXLAブックマークを削除できます。これによって、アプリケーションの再起動時に、新しいブックマークが作成されます。

更新を受信すると、MapMessage取得メソッドを使用してメッセージから情報を抽出し、アプリケーションで必要な処理を行うことができます。TimesTen XlaConstantsクラスでは、XLA更新メッセージの処理に使用にするために、更新タイプおよび特別なメッセージ・フィールドの定数が定義されています。

通常、メッセージに含める更新タイプを最初に決定します。MapMessageメソッドgetInt()を使用して__TYPEフィールドの内容を取得し、XlaConstantsクラスで定義されている数値定数とその値を比較します。

例3-7では(asyncJMSクイック・スタート・デモ)、メソッドonMessage()MapMessageオブジェクトから更新タイプを抽出し、更新が示している処理を表示します。

例3-7 更新タイプの決定

public void onMessage(Message message)
{
  MapMessage mapMessage = (MapMessage)message;
  String messageType = null;
  /* Standard output stream */
  private static PrintStream outStream = System.out;
 
  if (message == null)
  {
    errStream.println("MyListener: update message is null");
    return ;
  }
 
  try
  {
    outStream.println();
    outStream.println("onMessage: got a " + mapMessage.getJMSType() + " message");
 
    // Get the type of event (insert, update, delete, drop table, etc.).
    int type = mapMessage.getInt(XlaConstants.TYPE_FIELD);
    if (type == XlaConstants.INSERT)
    {
      outStream.println("A row was inserted.");
    }
    else if (type == XlaConstants.UPDATE)
    {
      outStream.println("A row was updated.");
    }
    else if (type == XlaConstants.DELETE)
    {
      outStream.println("A row was deleted.");
    }
    else
    {
 
      // Messages are also received for DDL events such as CREATE TABLE.
      // This program processes INSERT, UPDATE, and DELETE events,
      // and ignores the DDL events.
      return ;
    }    
  ...
  }
...
}

受信したメッセージのタイプがわかれば、アプリケーションにおける必要性に応じて、メッセージを処理できます。メッセージのすべてのフィールドのリストを取得するには、MapMessageメソッドgetMapNames()をコールします。メッセージの個々のフィールドを名前ごとに取得できます。

例3-8では(asyncJMSクイック・スタート・デモ)、列名を使用して、挿入、更新および削除メッセージから列値を抽出します。

例3-8 列値の抽出

/* Standard output stream */
private static PrintStream outStream = System.out;
...
if (type == XlaConstants.INSERT 
 || type == XlaConstants.UPDATE 
 || type == XlaConstants.DELETE)
{
 
  // Get the column values from the message.
  int cust_num = mapMessage.getInt("cust_num");
  String region = mapMessage.getString("region");
  String name = mapMessage.getString("name");
  String address = mapMessage.getString("address");
 
  outStream.println("New Column Values:");
  outStream.println("cust_num=" + cust_num);
  outStream.println("region=" + region);
  outStream.println("name=" + name);
  outStream.println("address=" + address);
}

XLA更新メッセージの内容の詳細は、「JMS/XLA MapMessageの内容」を参照してください。また、TimesTenの列の型がどのようにJMSデータ型にマップされているか、および列値を取得するために使用する取得メソッドについては、「データ型のサポート」を参照してください。

JMS/XLAアプリケーションの終了

XLAアプリケーションがトランザクション・ログからの読取りを終了した場合は、XLA接続をクローズして不要なブックマークを削除し、明示的にサブスクライブした表をサブスクライブ解除して、正常に終了する必要があります。

接続のクローズ

XLAへの接続をクローズするには、Connectionオブジェクトでclose()をコールします。

接続がクローズされた後、その接続、セッションまたはサブスクライバを使用しようとすると、IllegalStateExceptionエラーになります。その接続から受信したメッセージを継続して使用できますが、接続がクローズされた後、受信したメッセージのacknowledge()メソッドをコールすることはできません。

ブックマークの削除

停止時にXLAブックマークを削除するかどうかは、任意に選択できます。ブックマークを削除すると、トランザクション・ログ内の未読の更新レコードに関連するディスク領域を解放できます。

ブックマークを削除しない場合は、永続サブスクライバで再利用できます。永続サブスクライバが再接続するときにブックマークが使用可能な場合、サブスクライバは、以前の接続が終了した後に発行されたすべての未確認の更新を受信します。アプリケーションが読取りを行わないブックマークがある場合は、トランザクション・ログが増大し続け、データベースが消費するディスク領域が増加するので注意してください。

ブックマークを削除するには、JMS Sessionでunsubscribe()をコールすることにより、ttXlaBookmarkDelete組込みプロシージャが起動され、XLAブックマークが削除されます。


注意:

レプリケーション・エージェントが実行されている間は、レプリケートされるブックマークを削除できません。

表からのサブスクライブ解除

表に対するXLAパブリッシングをオフにするには、ttXlaUnsubscribe組込みプロシージャを使用します。ttXlaSubscribeを使用して表に対するXLAパブリッシングを有効にする場合は、アプリケーションを停止するときにttXlaUnsubscribeを使用して表からのサブスクライブ解除を行う必要があります。


注意:

表を削除する場合は、まず表からサブスクライブ解除します。

表からのサブスクライブ解除を行う場合は、次のように表を追跡するときに使用される表の名前とブックマークの名前を指定します。

ttXlaUnsubscribe(user.table, mybookmark)

たとえば、CallableStatementオブジェクトでttXlaUnSubscribeをコールするには、次の例のようにします。

例3-9 表からのサブスクライブ解除

Connection con;
CallableStatement cStmt;
...
cStmt = con.prepareCall("{call ttXlaUnSubscribe(user.table, mybookmark)}");
cStmt.execute();

JavaアプリケーションでTimesTen組込みプロシージャを使用する場合の詳細は、「プロシージャおよびファンクションを実行するためのCALLの使用」を参照してください。

レプリケーション・メカニズムとしてのJMS/XLAの使用

『Oracle TimesTen In-Memory Database開発者および管理者ガイド』で説明しているTimesTenでのレプリケーションは、多くのお客様のニーズを満たしますが、JMS/XLAを使用してデータベース間で更新をレプリケートすることも可能です。この方法で独自のレプリケーション・スキームをJMS/XLAに加え実装することはかなり複雑ですが、なんらかの理由でTimesTenでのレプリケーションが実現不能な場合は検討できます。

ターゲット・データベースへのJMS/XLAメッセージの適用

ソース・データベースでJMS/XLAメッセージが作成されます。このメッセージをターゲット・データベースに適用するには、メッセージからXLA記述子を抽出する必要があります。MapMessageインタフェースを使用して更新記述子を抽出します。

MapMessage message;
/*
 *...other code
 */
try {
  byte[]updateMessage=
    mapMessage.getBytes(XlaConstants.UPDATE_DESCRIPTOR_FIELD);
}
catch (JMSException jex){
/*
 *...other code
 */
}

ターゲット・データベースは、ソース・データベースとは別のシステムにインストールできます。更新記述子はバイト配列として返され、ネットワーク送信のためにシリアライズすることができます。

ソース・データベースからのオブジェクトを適用するために、ターゲット・データベースを表すターゲット・データベース・オブジェクトを作成する必要があります。TargetDataStoreImplクラスのインスタンスとして、myTargetDataStoreというターゲット・データベース・オブジェクトを作成します。次に例を示します。

TargetDataStore myTargetDataStore=
   new TargetDataStoreImpl("DSN=sampleDSN");

TargetDataStoreメソッドapply()を使用して、myTargetDataStoreにメッセージを適用します。次に例を示します。

myTargetDataStore.apply(updateDescriptor);

デフォルトでは、TimesTenは、更新を適用する前にターゲット・データベース上の競合を確認します。ターゲット・データベースに更新よりも遅い情報が含まれる場合、TargetDataStoreでは例外がスローされます。TimesTenで競合を確認しない場合は、TargetDataStoreメソッドsetUpdateConflictCheckFlag()を使用して動作を変更します。

デフォルトでは、TimesTenは、更新記述子に含まれているコミット・フラグとトランザクション境界に基づいてデータベースに対する更新をコミットします。アプリケーションで手動コミットを実行する場合は、setAutoCommitFlag()メソッドを使用して自動コミット・フラグを変更します。myTargetDataStoreに対して手動コミットを実行するには、次のコマンドを使用します。

myTargetDataStore.commit();

更新アプリケーションでエラーが発生した場合は、ロールバックを実行できます。myTargetDataStoreに対して次のコマンドを使用します。

myTargetDataStore.rollback();

次のコマンドを使用して、myTargetDataStoreをクローズします。

myTargetDataStore.close();

TargetDataStoreインタフェースの詳細は、「JMS/XLAレプリケーションAPI」を参照してください。

TargetDataStoreのエラー・リカバリ

TargetDataStoreを起動すると、一時的なエラーと永続的なエラーが発生する可能性があります。

一時的なエラーが発生すると、TargetDataStoreメソッドによって0(ゼロ)以外の値が返されます。アプリケーションは処理を再試行することができ、再適用する必要がある更新記述子を監視します。一時的なXLAのエラーの詳細は、『Oracle TimesTen In-Memory Database C開発者ガイド』のXLAのエラーの処理に関する項を参照してください。

永続的なエラーに対しては、TargetDataStoreメソッドによってJMSExceptionオブジェクトが返されます。アプリケーションが永続的なエラーを受信すると、データベースが有効かどうかを確認する必要があります。データベースが無効な場合、ターゲット・データベース・オブジェクトを閉じ、新しいものを作成する必要があります。その他のタイプの永続的なエラーには、手動での操作が必要になる場合があります。

次の例に、TargetDataStoreオブジェクトからエラーをリカバリする方法を示します。

例3-10 エラーのリカバリ

TargetDataStore theTargetDataStore;
byte[] updateDescriptor;
int rc;

// Other code
try {
  ...
  if ( (rc = theTargetDataStore.apply(updateDescriptor) ) == 0 ) {
    // Apply successful.
  }
  else {
    // Transient error. Retry later.
  }
 }
catch (JMSException jex) {
  if (theTargetDataStore.isDataStoreValid() ) {
    // Database valid; permanent error that may need Administrator intervention.
  }
  else {
    try {
      theTargetDataStore.close();
  }
  catch (JMSException closeEx) {
    // Close errors are not usual. This may need Administrator intervention.
  }
}