日本語PDF

11 Oracle Java Message Serviceの概要

次のトピックでは、Oracle Database Advanced Queuing (AQ)へのOracle Java Message Service (JMS)インタフェースについて説明します。

JMSおよびOracle JMSの一般的な機能

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

JMSコネクションおよびセッション

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

ConnectionFactoryオブジェクト

ConnectionFactoryは、管理者によって定義された接続構成パラメータの集合をカプセル化します。クライアントはこれを使用してJMSプロバイダとの接続を確立します。この場合、Oracle Databaseの一部であるOracle JMSがJMSプロバイダです。

ConnectionFactoryオブジェクトには、次の3種類があります。

  • ConnectionFactory

  • QueueConnectionFactory

  • TopicConnectionFactory

AQjmsFactoryを使用したConnectionFactoryオブジェクトの取得

AQjmsFactoryクラスを使用して、ConnectionFactoryQueueConnectionFactoryまたはTopicConnectionFactoryオブジェクトに対するハンドルを取得できます。

Point-to-Point操作とパブリッシュ・サブスクライブ操作の両方をサポートしているConnectionFactoryを取得するには、AQjmsFactory.getConnectionFactory()を使用します。QueueConnectionFactoryを取得するには、AQjmsFactory.getQueueConnectionFactory()を使用します。TopicConnectionFactoryを取得するには、AQjmsFactory.getTopicConnectionFactory()を使用します。

ConnectionFactoryQueueConnectionFactoryまたはTopicConnectionFactoryは、ホスト名、ポート番号、SIDドライバまたはJDBC URLおよびプロパティを使用して作成できます。

JNDIを使用したConnectionFactoryオブジェクトの検索

JMS管理者は、Lightweight Directory Access Protocol(LDAP)サーバーにConnectionFactoryオブジェクトを登録できます。JMSでJava Naming and Directory Interface(JNDI)の検索を使用可能にするには、次の設定が必要です。

  1. データベースの登録

    Oracle Databaseサーバーのインストール時に、データベースをLDAPサーバーに登録する必要があります。これは、Database Configuration Assistant (DBCA)を使用して実行できます。図11-1に、LDAPサーバー内のOracle Database Advanced Queuingエントリの構造を示します。ConnectionFactory情報は<cn=OracleDBConnections>の下に格納され、トピックおよびキューは<cn=OracleDBQueues>の下に格納されます。

    図11-1 LDAPサーバー内のOracle Database Advanced Queuingエントリの構造

    図11-1の説明が続きます
    「図11-1 LDAPサーバー内のOracle Database Advanced Queuingエントリの構造」の説明
  2. パラメータGLOBAL_TOPIC_ENABLEDを設定します。

    データベースのGLOBAL_TOPIC_ENABLEDシステム・パラメータをTRUEに設定する必要があります。これによって、Oracle Database Advanced Queuingで作成されたすべてのキューおよびトピックが自動的にLDAPサーバーに登録されます。このパラメータは、ALTER SYSTEM SET GLOBAL_TOPIC_ENABLED = TRUEを使用して設定できます。

  3. ConnectionFactoryオブジェクトを登録します

    データベースを設定してLDAPサーバーが使用できるようになると、JMS管理者はAQjmsFactory.registerConnectionFactory()を使用して、LDAPにConnectionFactoryQueueConnectionFactoryおよびTopicConnectionFactoryの各オブジェクトを登録できます。

    登録には次のいずれかの方法を使用します。

    • 直接LDAPサーバーに接続

      LDAPにコネクション・ファクトリを登録するには、ユーザーにGLOBAL_AQ_USER_ROLEが必要です。

      LDAPに直接接続するには、registerConnectionFactoryメソッドのパラメータに、LDAPコンテキスト、ConnectionFactoryの名前、QueueConnectionFactoryの名前、TopicConnectionFactoryの名前、ホスト名、データベースSID、ポート番号、JDBCドライバ(ThinまたはOCI8)およびファクトリ・タイプ(キューまたはトピック)を含める必要があります。

    • データベース・サーバーを介してLDAPに接続

      ユーザーはOracle Databaseにログインしてから、データベースによるLDAPエントリの更新ができます。ユーザーが、データベースにログインしてこの操作を実行するには、AQ_ADMINISTRATOR_ROLEを取得する必要があります。

      データベースを介してLDAPに接続するには、registerConnectionFactoryメソッドのパラメータに、AQ_ADMINISTRATOR_ROLEを持つユーザーへのJDBCコネクション、ConnectionFactoryの名前、QueueConnectionFactoryの名前、TopicConnectionFactoryの名前、ホスト名、データベースSID、ポート番号、JDBCドライバ(ThinまたはOCI8)およびファクトリ・タイプ(キューまたはトピック)を含める必要があります。

JMSコネクション

JMSコネクションは、クライアントとJMSプロバイダの間のアクティブなコネクションを表します。JMSコネクションによって、次に示すいくつかの重要なサービスが実行されます。

  • JMSプロバイダとのオープン・コネクションまたはコネクション・プールのいずれかをカプセル化します。

  • クライアントとプロバイダのサービス・デーモン間のオープンなTCP/IPソケットを表します。

  • コネクション確立時に、クライアントを認証するための構造を提供します。

  • Sessionsを作成します

  • コネクション・メタデータを提供します。

  • オプションのExceptionListenerをサポートします。

データベースへのJMSコネクションは、createConnection()createQueueConnection()またはcreateTopicConnection()を起動し、ConnectionFactoryオブジェクト、QueueConnectionFactoryオブジェクトまたはTopicConnectionFactoryオブジェクトにそれぞれパラメータusernameおよびpasswordを渡して作成できます。

次に、Connectionオブジェクトでサポートされているメソッドのいくつかを示します。

  • start()

    このメソッドは、着信メッセージの配信を開始または再開します。

  • stop()

    このメソッドは、着信メッセージの配信を一時停止します。Connectionオブジェクトが停止すると、すべてのメッセージ・コンシューマへの配信は禁止されます。また、同期受信のブロックおよびメッセージは、メッセージ・リスナーに配信されません。

  • close()

    このメソッドは、JMSセッションをクローズして、関連付けられたすべてのリソースを解放します。

  • createSession(true, 0)

    このメソッドは、JMS Connectionインスタンスを使用してJMS Sessionを作成します。

  • createQueueSession(true, 0)

    このメソッドはQueueSessionを作成します。

  • createTopicSession(true, 0)

    このメソッドはTopicSessionを作成します。

  • setExceptionListener(ExceptionListener)

    このメソッドは、Connectionの例外リスナーを設定します。問題が非同期でクライアントに通知されます。メッセージを処理するのみのConnectionの場合、その失敗を確認する他の方法はありません。

  • getExceptionListener()

    このメソッドは、このConnectionExceptionListenerを取得します。

JMSクライアントは、通常1つのConnection、1つのSession、複数のMessageProducerおよびMessageConsumerオブジェクトを作成します。現在のバージョンでは、次の場合を除いて、1つのConnectionにつき1つのオープンSessionのみが許可されています。

  • JDBC OCI8ドライバを使用してJMSコネクションを作成する場合

  • ユーザーが、JMSコネクションの作成時にOracleOCIConnectionPoolインスタンスを提供する場合

Connectionは停止モードで作成されます。この状態では、メッセージを受信できません。通常、設定が完了するまで、Connectionを停止モードにしておきます。その時点でConnection start()メソッドがコールされ、メッセージがConnectionコンシューマに配信され始めます。このような設定規則を確立することにより、クライアントが設定されている最中の非同期メッセージ配信の結果、発生するクライアントの混乱を最小限に止められます。

Connectionを起動し、続けて設定を実行できます。これを実行するクライアントは、設定処理中に非同期メッセージの配信処理の準備をする必要があります。MessageProducerは、Connectionが停止中でもメッセージを送信できます。

JMSセッション

JMS Sessionは、メッセージの作成および処理用の単一スレッドのコンテキストです。これは、Java Virtual Machine(JVM)の外でプロバイダ・リソースを割り当てますが、軽量なJMSオブジェクトとみなされます。

Sessionには、次の役割があります。

  • MessageProducerおよびMessageConsumerオブジェクトのファクトリを構成します。

  • 宛先オブジェクト(キュー/トピック)に対するハンドルの取得方法を提供します。

  • プロバイダが最適化したメッセージ・ファクトリを提供します。

  • セッションのMessageProducerおよびMessageConsumerオブジェクトにまたがる作業を組み合せる一連のトランザクションをサポートし、これらを単位に構成します。

  • セッションが処理および作成するメッセージのシリアル順序を定義します。

  • セッションに登録されたMessageListenerオブジェクトの実行をシリアル化します。

Oracle Database 10gでは、JDBC thinまたはJDBC thick(OCI)ドライバのいずれかを使用すると、単一のJMS Connectionを使用して、リソースが許すかぎり多くのJMS Sessionを作成できます。

プロバイダが、JVM外のSessionのためのリソースを割り当てることができるため、クライアントはリソースが必要ないときはこれらを閉じる必要があります。ガベージ・コレクションによる最終的なリソースの解放を待つ必要はありません。Sessionが作成したMessageProducerおよびMessageConsumerオブジェクトについても同様です。

Sessionオブジェクトのメソッドには、次のものが含まれます。

  • commit()

    このメソッドは、トランザクションで実行されるすべてのメッセージをコミットして、現在保持されているロックを解放します。

  • rollback()

    このメソッドは、トランザクションで実行されたすべてのメッセージをロールバックして、現在保持されているロックを解放します。

  • close()

    このメソッドはSessionをクローズします。

  • getDBConnection()

    このメソッドは、基礎となるJDBCコネクションに対するハンドルを取得します。このハンドルを使用して、他のSQL DML操作を同じSessionの一部として実行できます。このメソッドは、Oracle JMSに固有です。

  • acknowledge()

    このメソッドは、非トランザクション・セッションでメッセージの受信を承認します。

  • recover()

    このメソッドは、非トランザクション・セッションでメッセージの配信を再開します。セッション中に配信された一連のメッセージは、最後に承認されたメッセージの後でリセットされます。

Oracle JMSの拡張例は、次のとおりです。

  • createQueueTable()

    このメソッドはキュー表を作成します。

  • getQueueTable()

    このメソッドは既存のキュー表に対するハンドルを取得します。

  • createQueue()

    このメソッドはキューを作成します。

  • getQueue()

    このメソッドは既存のキューに対するハンドルを取得します。

  • createTopic()

    このメソッドはトピックを作成します。

  • getTopic()

    このメソッドは既存のトピックに対するハンドルを取得します。

どの拡張機能を使用する場合も、SessionオブジェクトをAQjmsSessionにキャストする必要があります。

注意:

JMS仕様では、開始されていないJMS Connectionインスタンスで受信が完了したとき、プロバイダによりNULLメッセージが返されることを要求します。

javax.jms.Connectionインスタンスの作成後、start()メソッドをそのインスタンスにコールしてメッセージを受信できるようにする必要があります。コネクション確立後で実際に受信する前に、t_conn.start();などの行を追加するとメッセージを受信できます。

JMS宛先

Destinationは、クライアントがメッセージの送信先および受信元の指定に使用するオブジェクトです。DestinationオブジェクトはQueueまたはTopicに指定できます。Oracle Database Advanced Queuingでは、特定のデータベースのschema.queueにマップされます。Queueは単一コンシューマ・キューに、Topicはマルチ・コンシューマ・キューにマップします。

JMSセッションを使用したDestinationオブジェクトの取得

Destinationオブジェクトは、Sessionオブジェクトからドメイン固有の次のSessionメソッドを使用して作成されます。

  • AQjmsSession.getQueue(queue_owner, queue_name)

    このメソッドはJMSキューに対するハンドルを取得します。

  • AQjmsSession.getTopic(topic_owner, topic_name)

    このメソッドはJMSトピックに対するハンドルを取得します。

JNDIを使用したDestinationオブジェクトの検索

LDAPサーバーにスキーマ・オブジェクトを登録するようにデータベースを設定できます。データベースがLDAPを使用できるように設定され、GLOBAL_TOPIC_ENABLEDパラメータがTRUEに設定されている場合、すべてのJMSキューおよびトピックは、作成時に自動的にLDAPサーバーに登録されます。管理者は、LDAPに登録されたキューおよびトピックの別名を作成することもできます。LDAPに登録されたキューおよびトピックは、JNDIを介してキューまたはトピックの名前または別名を使用してルックアップできます。

JMS宛先メソッド

Destinationオブジェクトのメソッドには、次のものが含まれます。

  • alter()

    このメソッドはキューまたはトピックを変更します。

  • schedulePropagation()

    このメソッドは、ソースから宛先への伝播をスケジューリングします。

  • unschedulePropagation()

    このメソッドは、スケジュール済伝播のスケジュールを解除します。

  • enablePropagationSchedule()

    このメソッドは、伝播スケジュールを有効化します。

  • disablePropagationSchedule()

    このメソッドは、伝播スケジュールを無効化します。

  • start()

    このメソッドはキューまたはトピックを開始します。キューは、エンキューまたはデキューを可能にするために開始されます。トピックは、パブリッシュまたはサブスクライブを可能にするために開始できます。

  • stop()

    このメソッドはキューまたはトピックを停止します。キューは、エンキューまたはデキューを実行不可にするために停止できます。トピックは、パブリッシュまたはサブスクライブを実行不可にするために停止できます。

  • drop()

    このメソッドはキューまたはトピックを削除します。

JMSでのシステム・レベルのアクセス制御

Oracle8i以上では、すべてのキューイング操作に対してシステム・レベルのアクセス制御をサポートします。この機能によって、アプリケーション設計者またはDBAは、ユーザーをキュー管理者にできます。キュー管理者は、データベースのどのキューに対してもJMSインタフェース(管理および操作)を起動できます。これによって、データベース上のキュー全体に対するすべての管理スクリプトを1つのスキーマで管理できるため、管理作業が容易になります。

メッセージが宛先キューに届くと、ソース・キューのスキーマ名に基づいたセッションによって、新しく届いたメッセージが宛先キューにエンキューされます。つまり、ソース・キューのスキーマに宛先キューに対するエンキュー権限を付与する必要があります。

リモートの宛先キューに伝播するために、エージェント構造体のアドレス・フィールドのデータベース・リンクに指定されたログイン・ユーザーには、ENQUEUE_ANY権限を付与するか、または宛先キューに対するエンキュー権限を付与する必要があります。ただし、データベース・リンクのログイン・ユーザーが宛先のキュー表を所有している場合はどのような明示的な権限も付与する必要はありません。

JMSでの宛先レベルのアクセス制御

Oracle8i以上では、エンキューおよびデキュー操作に対してキュー・レベルまたはトピック・レベルのアクセス制御をサポートしています。この機能によって、アプリケーション設計者は、あるスキーマに作成されたキューおよびトピックを他のスキーマで実行中のアプリケーションから保護できます。そのキューまたはトピックが属するスキーマの外で実行しているアプリケーションには、最小限のアクセス権限のみを付与できます。キューまたはトピックに対するアクセス権限として、ENQUEUEDEQUEUEおよびALLがサポートされています。

JMSでの保存およびメッセージ履歴

メッセージは、相互に関連していることがよくあります。たとえば、あるメッセージを処理した結果として他のメッセージが生成された場合、両者は関連付けられています。アプリケーション設計者としては、そのような関連を追跡することが必要な場合があります。Oracle Database Advanced Queuingでは、ユーザーがメッセージをキュー表に保持し、分析のためにSQLで問合せできます。

保存機能およびメッセージ識別子とともに、メッセージ・ジャーナルがOracle Database Advanced Queuingによって自動作成され、追跡ジャーナルまたはイベント・ジャーナルをコールできます。保存、メッセージ識別子およびSQL問合せの協調によって、強力なメッセージ・ウェアハウスを構築できます。

JMSでのOracle Real Application Clustersのサポート

Oracle Database 12cリリース1 (12.1)では、Advanced Queuingに、高性能でスケーラブルなJMSシャード・キューが導入されました。シャード・キューとは、システムで管理されているパーティション化を使用して、独立した複数の物理キューに分割される1つの論理キューです。シャード・キューは、Oracle RACインスタンス全体で使用されるキュー、エンキュー率またはデキュー率の高いキュー、またはサブスクライバの多いキューについて推奨されるJMSキューです。詳細は、「シャード・キューおよびOracle Real Application Clusters (Oracle RAC)」を参照してください。

非シャード・キューの場合は、Oracle Real Application Clusters (Oracle RAC)を使用して、各インスタンスを別々のキューで管理できるようにすることで、Oracle Database Advanced Queuingのパフォーマンスを向上できます。このためには、キューを格納するキュー表に様々なインスタンス・アフィニティ(作業環境)を指定します。これによって、様々なキュー/トピックに対するキュー操作(エンキューまたはデキュー)またはトピック操作(パブリッシュ・サブスクライブ)を並行して行うことができるようになります。

Oracle Database Advanced Queuingのキュー・モニター・プロセスは、キュー表のインスタンス・アフィニティを継続的に監視します。キュー・モニターは指定されたプライマリ・インスタンスが使用可能な場合はそれにキュー表の所有権を割り当て、失敗した場合は指定されたセカンダリ・インスタンスに割り当てます。

キュー表を所有しているインスタンスが終了すると、キュー・モニターはセカンダリ・インスタンスなどの適切なインスタンスに所有者を変更します。

Oracle Database Advanced Queuingの伝播はOracle Real Application Clustersでも使用できますが、これはユーザーに対して透過的です。伝播スケジュールのジョブ・アフィニティは、それぞれのキュー表のアフィニティと同じ値に設定されます。このように、キュー表を所有するインスタンスに対応付けられたjob_queue_processは、そのキュー表に格納されているキューからの伝播を処理し、ping操作を最小限に抑えます。

JMSでの統計ビューのサポート

各インスタンスは、それぞれのOracle Database Advanced Queuing統計情報をシステム・グローバル領域(SGA)に所有し、他のインスタンスによって収集された統計については認識しません。そのため、インスタンスがGV$AQビューを問い合せると、その他のすべてのインスタンスからそれぞれのその時点の統計情報が問合せ元のインスタンスに集まります。

GV$AQビューは、待機中、準備完了または期限切れの各メッセージ数を必要なときにいつでも問い合せることができます。また、メッセージが処理されるまでの平均待機秒数も表示します。

JMSでの構造化ペイロード/メッセージの型

JMSメッセージは、ヘッダー、プロパティおよび本体で構成されています。

ヘッダーは、クライアントおよびプロバイダの両方でメッセージの識別およびルーティングに使用される値が含まれるヘッダー・フィールドで構成されています。すべてのメッセージは、同じ一連のヘッダー・フィールドをサポートしています。

プロパティは、オプションのヘッダー・フィールドです。JMSによって定義された標準プロパティの他に、プロバイダ固有およびアプリケーション固有のプロパティを含めることもできます。

本体はメッセージ・ペイロードです。JMSは、様々な型のメッセージ・ペイロードおよびJMSで指定されたメッセージ型のJMSメッセージを格納できる型を定義します。

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

JMSメッセージ・ヘッダー

JMSメッセージ・ヘッダーには、次のフィールドが含まれます。

  • JMSDestination

    このフィールドには、メッセージの送信先が含まれます。Oracle Database Advanced Queuingでは、これは送信先キューまたはトピックに相当します。Sendメソッドの完了後にJMSによって設定されるDestination型です。

  • JMSDeliveryMode

    このフィールドは、メッセージのログが記録されるかどうかを決定します。JMSでは、PERSISTENT送信(メッセージが決まった記憶域にロギングされる)およびNONPERSISTENT送信(メッセージがロギングされない)をサポートしています。Sendメソッドの完了後にJMSによって設定されるINTEGERです。JMSでは、クライアントが指定したJMSDeliveryModeの値をオーバーライドするよう管理者がJMSを構成することが可能です。

  • JMSMessageID

    このフィールドは、プロバイダ内のメッセージを一意に識別します。すべてのメッセージIDは先頭に文字列ID:を使用する必要があります。Sendメソッドの完了後にJMSによって設定されるString型です。

  • JMSTimeStamp

    このフィールドには、送信先のプロバイダにメッセージが渡された時間が含まれます。Oracle Database Advanced Queuingのメッセージのエンキュー時間にマッピングされます。Sendメソッドの完了後にJMSによって設定されるLong型です。

  • JMSCorrelationID

    このフィールドは、クライアントがメッセージを別のメッセージにリンクするために使用できます。JMSクライアントによって設定されるString型です。

  • JMSReplyTo

    このフィールドには、メッセージ送信時にクライアントが指定するDestination型が含まれます。クライアントはoracle.jms.AQjmsAgentjavax.jms.Queueまたはjavax.jms.Topicを使用できます。

  • JMSType

    このフィールドには、送信時にクライアントが指定するメッセージ・タイプの識別子が含まれます。これはString型です。移植性を高めるために、JMSTypeに記号値を使用することをお薦めします。

  • JMSExpiration

    このフィールドは、非Java EE準拠モードでは、エンキュー時間とTimeToLiveの合計です。準拠モードでは、デキューされたメッセージのJMSExpirationヘッダー値は、メッセージのエンキュー時のJMSTimeStamp (ミリ秒単位のグリニッジ標準時)とTimeToLive (ミリ秒単位)の合計です。Sendメソッドの完了後にJMSによって設定されるLong型です。JMSでは、クライアントが指定したJMSExpirationの値をオーバーライドするよう管理者がJMSを構成することが可能です。

  • JMSPriority

    このフィールドには、メッセージの優先度が含まれます。Sendメソッドの完了後にJMSによって設定されるINTEGERです。Java EE準拠モードでは、優先度に使用できる値は0から9で、9の優先度が最も高く、4がデフォルトで、Sun Microsystem JMS 1.1標準に準拠しています。デフォルトは非準拠モードです。JMSでは、クライアントが指定したJMSPriorityの値をオーバーライドするよう管理者がJMSを構成することが可能です。

  • JMSRedelivered

    このフィールドは、JMSプロバイダによって設定されたブールです。

関連項目:

Java EEの準拠

JMSメッセージ・プロパティ

JMSプロパティは、クライアントによって明示的に設定されるか、またはJMSプロバイダによって自動的に設定されます(通常、これらは読取り専用です)。JMSプロパティには、SendおよびReceive操作に指定されたパラメータを使用して設定されるものもあります。

プロパティで、メッセージにオプションのヘッダー・フィールドを追加できます。プロパティによって、クライアントは、messageSelectorを使用して、クライアントのかわりにJMSプロバイダにアプリケーション固有基準を使用してメッセージを選択させることができます。プロパティ名は文字列で、値はBooleanbyteshortintlongfloatdoubleおよびstringです。

JMS定義のプロパティは、すべてJMSXで始まります。次のものがあります。

  • JMSXUserID

    このフィールドは、メッセージの送信元ユーザーの識別情報です。Sendメソッドの完了後にJMSによって設定されるString型です。

  • JMSXAppID

    このフィールドは、メッセージの送信元アプリケーションの識別情報です。Sendメソッドの完了後にJMSによって設定されるString型です。

  • JMSXDeliveryCount

    このフィールドは、メッセージの送信試行回数です。Sendメソッドの完了後にJMSによって設定されるIntegerです。

  • JMSXGroupid

    このフィールドは、メッセージが属するメッセージ・グループの識別情報です。JMSクライアントによって設定されるString型です。

  • JMSXGroupSeq

    このフィールドは、グループ内のメッセージの順序番号です。JMSクライアントによって設定されるInteger型です。

  • JMSXRcvTimeStamp

    このフィールドは、コンシューマにメッセージが配信された時間(デキュー時間)です。Receiveメソッドの完了後にJMSによって設定されるString型です。

  • JMSXState

    このフィールドは、プロバイダによって設定されたメッセージ状態です。メッセージ状態は、WAITINGREADYEXPIREDまたはRETAINEDです。

Oracle固有のJMSプロパティは、すべてJMS_Oracleで始まります。次のものがあります。

  • JMS_OracleExcpQ

    このフィールドは、元の宛先に配信できないメッセージを送信するキュー名です。JMSクライアントによって設定されるString型です。EXCEPTIONタイプの宛先のみをJMS_OracleExcpQプロパティで指定できます。

  • JMS_OracleDelay

    このフィールドは、メッセージの配信を遅延する時間(秒単位)です。JMSクライアントによって設定されるInteger型です。これは、メッセージの配信順序に影響を与える可能性があります。

  • JMS_OracleOriginalMessageId

    このフィールドは、メッセージがある宛先から別の宛先に伝播された場合に、ソースのメッセージのメッセージ識別子に設定されます。JMSプロバイダによって設定されるString型です。メッセージが伝播されていない場合、このプロパティはJMSMessageIdと同じ値です。

クライアントは、プロパティを定義することによって、メッセージにヘッダー・フィールドを追加できます。これらのプロパティをmessageSelectorで使用して特定のメッセージを選択できます。

JMSメッセージ本体

JMSでは、次の5つのフォーマットのメッセージ本体が提供されます。

StreamMessage

StreamMessageオブジェクトは、Javaプリミティブのストリームの送信に使用されます。格納と読取りは順次的に行われます。これはMessageから継承し、StreamMessage本文を追加します。メソッドは主にjava.io.DataInputStreamjava.io.DataOutputStreamのメソッドに基づいています。

基本データ型の値は、それぞれの型のメソッドを使用して、明示的に読込みまたは書込みできます。抽象的なオブジェクトとして読込みまたは書込みすることもできます。StreamMessageオブジェクトを使用するには、SYS.AQ$_JMS_STREAM_MESSAGEまたはAQ$_JMS_MESSAGEペイロード型を持つキュー表を作成します。

StreamMessageオブジェクトは、表11-1に示す変換をサポートします。行の型として書き込まれる値は、列の型として読み込むことができます。

表11-1 StreamMessageの変換

入力 Boolean byte short char int long float double String byte[]

Boolean

X

-

-

-

-

-

-

-

X

-

byte

-

X

X

-

X

X

-

-

X

-

short

-

-

X

-

X

X

-

-

X

-

char

-

-

-

X

-

-

-

-

X

-

int

-

-

-

-

X

X

-

-

X

-

long

-

-

-

-

-

X

-

-

X

-

float

-

-

-

-

-

-

X

X

X

-

double

-

-

-

-

-

-

-

X

X

-

string

X

X

X

X

X

X

X

X

X

-

byte[]

-

-

-

-

-

-

-

-

-

X

BytesMessage

BytesMessageオブジェクトは、1つの未解釈バイトのストリームを含むメッセージを送信する場合に使用します。これはMessageから継承し、BytesMessage本文を追加します。メッセージの受信者が、そのバイト列を解析します。メソッドは主にjava.io.DataInputStreamjava.io.DataOutputStreamのメソッドに基づいています。

これは、クライアントが既存のメッセージ・フォーマットをコード化するためのメッセージ型です。可能であれば、かわりに他の自己定義メッセージ型を使用してください。

基本データ型の値は、それぞれの型のメソッドを使用して、明示的に書込みができます。また、抽象的なオブジェクトとして書き込むこともできます。BytesMessageオブジェクトを使用するには、SYS.AQ$_JMS_BYTES_MESSAGEまたはAQ$_JMS_MESSAGEペイロード型を持つキュー表を作成します。

MapMessage

MapMessageオブジェクトは、名前がString型で値がJava基本データ型である名前/値ペアの集合を送信する場合に使用します。このエントリには、名前を指定して順次的またはランダムにアクセスできます。エントリの順序は定義されません。これはMessageから継承し、MapMessage本文を追加します。基本データ型の値は、それぞれの型のメソッドを使用して、明示的に読込みまたは書込みできます。抽象的なオブジェクトとして読込みまたは書込みすることもできます。

MapMessageオブジェクトを使用するには、SYS.AQ$_JMS_MAP_MESSAGEまたはAQ$_JMS_MESSAGEペイロード型を持つキュー表を作成します。MapMessageオブジェクトは、表11-2に示す変換をサポートします。この表の「X」は、行の型として書き込まれる値を列の型として読み取ることができることを意味します。

表11-2 MapMessageの変換

入力 Boolean byte short char int long float double String byte[]

Boolean

X

-

-

-

-

-

-

-

X

-

byte

-

X

X

-

X

X

-

-

X

-

short

-

-

X

-

X

X

-

-

X

-

char

-

-

-

X

-

-

-

-

X

-

int

-

-

-

-

X

X

-

-

X

-

long

-

-

-

-

-

X

-

-

X

-

float

-

-

-

-

-

-

X

X

X

-

double

-

-

-

-

-

-

-

X

X

-

string

X

X

X

X

X

X

X

X

X

-

byte[]

-

-

-

-

-

-

-

-

-

X

TextMessage

TextMessageオブジェクトは、java.lang.StringBufferを含むメッセージを送信する場合に使用します。これはMessageから継承し、TextMessage本文を追加します。テキスト情報は、getText()およびsetText(...)メソッドを使用して読込みまたは書込みができます。TextMessageオブジェクトを使用するには、SYS.AQ$_JMS_TEXT_MESSAGEまたはAQ$_JMS_MESSAGEペイロード型を持つキュー表を作成します。

ObjectMessage

ObjectMessageオブジェクトは、シリアライズ可能なJavaオブジェクトを含むメッセージを送信する場合に使用します。これはMessageから継承し、単一のJava参照を含む本文を追加します。シリアライズ可能なJavaオブジェクトのみ使用できます。Javaオブジェクトのコレクションを送信する必要がある場合、JDK 1.4で提供されているコレクション・クラスのいずれかを使用できます。オブジェクトは、getObject()メソッドおよびsetObject(...)メソッドを使用して読込みまたは書込みできます。ObjectMessageオブジェクトを使用する場合、SYS.AQ$_JMS_OBJECT_MESSAGEまたはAQ$_JMS_MESSAGEペイロード型でキュー表を作成します。

AdtMessage

AdtMessageオブジェクトは、Oracleのオブジェクト型に対応するJavaオブジェクトを含むメッセージを送信する場合に使用します。これらのオブジェクトはMessageから継承され、CustomDatumまたはORADataインタフェースを実装するJavaオブジェクトを含む本体を追加します。

AdtMessageオブジェクトを使用するには、Oracleのオブジェクト型としてのペイロード型を持つキュー表を作成します。AdtMessageのペイロードは、getAdtPayloadおよびsetAdtPayloadメソッドを使用して、読取りおよび書込みができます。

AdtMessageオブジェクトを使用してSYS.XMLType型のキューへメッセージを送信することもできます。oracle.xdb.XMLTypeクラスを使用してメッセージを作成する必要があります。

AdtMessageオブジェクトの場合、クライアントが次を取得できます。

  • JMSXDeliveryCount

  • JMSXRecvTimeStamp

  • JMSXState

  • JMS_OracleExcpQ

  • JMS_OracleDelay

関連項目:

CustomDatumインタフェースおよびORADataインタフェースの詳細は、『Oracle Database Java開発者ガイド』を参照してください。

異なるメッセージ型でのメッセージ・プロパティの使用

次のメッセージ・プロパティは、クライアントがsetPropertyコールを使用して設定できます。StreamMessageBytesMessageObjectMessageTextMessageおよびMapMessageオブジェクトの場合、クライアントによって次の設定ができます。

  • JMSXAppID

  • JMSXGroupID

  • JMSXGroupSeq

  • JMS_OracleExcpQ

  • JMS_OracleDelay

AdtMessageオブジェクトの場合、クライアントによって次の設定ができます。

  • JMS_OracleExcpQ

  • JMS_OracleDelay

次のメッセージ・プロパティは、クライアントがgetPropertyコールを使用して取得できます。StreamMessageBytesMessageObjectMessageTextMessageおよびMapMessageオブジェクトの場合、クライアントが次を取得できます。

  • JMSXuserID

  • JMSXAppID

  • JMSXDeliveryCount

  • JMSXGroupID

  • JMSXGroupSeq

  • JMSXRecvTimeStamp

  • JMSXState

  • JMS_OracleExcpQ

  • JMS_OracleDelay

  • JMS_OracleOriginalMessageID

Oracle JMSを使用したバッファ済メッセージ

メッセージの送信時にdeliveryModeとしてNON_PERSISTENTを指定すると、非永続JMSメッセージを送信できます。JMS非永続メッセージは決まった記憶域に記録する必要がないため、JMSシステム障害が発生すると消失する可能性があります。JMS非永続メッセージはOracle Database Advanced Queuingで使用可能なバッファ済メッセージに類似していますが、両者には重要な相違点も存在します。

注意:

Oracle JMSの非永続メッセージを、Oracle Database 10gリリース2(10.2)で非推奨になったOracle Database Advanced Queuingの非永続キューと混同しないでください。

トランザクションのコミットとクライアントの確認

JMSのdeliveryModeは、メッセージのトランザクション属性と直交します。JMS非永続メッセージは、処理済セッションまたは非処理済セッションで送受信できます。JMS非永続メッセージを処理済セッションで送受信する場合、JMS操作の効果は処理済セッションのコミット後にのみ参照可能です。CLIENT_ACKNOWLEDGE確認モードの非処理済セッションで受信する場合、このメッセージの受信による効果は、クライアントがメッセージを確認した後にのみ参照可能です。確認されない場合、メッセージは削除されず、クライアントがSession.recoverをコールすると再配信されます。

これに対して、Oracle Database Advanced Queuingのバッファ済メッセージでは、このようなトランザクションまたは確認の概念はサポートされません。バッファ済メッセージの送受信は、どちらもIMMEDIATE可視性モードで実行する必要があります。したがって、セッションがコミットされたかどうかやメッセージが確認されたかどうかは関係なく、ユーザーは送受信操作の効果を即時に参照できます。

各種API

通常のJMS送信およびパブリッシュ・メソッドで送信されるメッセージは、Oracle Database Advanced Queuingでは永続メッセージとして扱われます。通常のJMS受信メソッドは、AQ永続メッセージのみを受信します。バッファ済メッセージを送受信するには、Oracle拡張APIであるbufferSendbufferPublishおよびbufferReceiveを使用する必要があります。

関連項目:

bufferSendbufferPublishおよびbufferReceiveの詳細は、Oracle Databaseアドバンスト・キューイングJava APIリファレンスを参照してください

ペイロード制限

バッファ済メッセージのOracle Database Advanced Queuing実装では、LOB属性はサポートされていません。このため、5種類の標準JMSメッセージのペイロードには次の制限が適用されます。

  • JMS TextMessageのペイロードは4000バイト以内です。

    Oracle JMSのキャラクタ・セット変換時には、テキスト・ペイロードをデータベースに格納するためにVARCHARのかわりにCLOBを使用するように控え目な選択が必要になる場合があるため、データベース・キャラクタ・セットによってはこの上限値がさらに低くなる場合があります。

  • JMS BytesMessageのペイロードは2000バイト以内です。

  • JavaでシリアライズされたJMS ObjectMessageStreamMessageおよびMapMessageデータは、2000バイト以内である必要があります。

  • 他のすべてのOracle JMS ADTメッセージの場合、対応するOracleデータベースADTにLOB属性を含めることはできません。

各種定数

表11-3に示すように、Oracle Database Advanced QueuingとOracle JMSのAPIでは、バッファ済メッセージと永続メッセージの指定に使用される数値が異なります。

表11-3 Oracle Database AQとOracle JMSのバッファ済メッセージ定数

API 永続メッセージ バッファ済メッセージ

Oracle Database Advanced Queuing

PERSISTENT := 1

BUFFERED :=2

Oracle JMS

PERSISTENT := 2

NON_PERSISTENT := 1

JMSのバッファ済メッセージ

バッファ済メッセージでは、JMSメッセージ標準が完全にサポートされています。Oracle JMSでは、それらの標準がいくつかの方法で拡張されています。

JMSバッファ済メッセージのエンキュー

Oracle JMSでは、永続メッセージおよびバッファ済メッセージを同じJMSキュー/トピックにエンキューできるように、個別のメッセージにJMSDeliveryModeを設定することによって、アプリケーションはバッファ済メッセージを送信できます。

Oracle JMSのバッファ済メッセージは、エンキュー時刻、優先順位またはその両方で順序付けできます。順序付けは異なるメッセージ・タイプ間では適用されません。このため、たとえば、後に送信された永続メッセージが前に送信されたバッファ済メッセージより前に配信されることがあります。Oracle JMSのバッファ済メッセージでは、期限切れもサポートされます。

JMSバッファ済メッセージのデキュー

JMSでは、JMSサブスクライバが両方のメッセージ・タイプを対象にできるように、サブスクライバが永続メッセージのみまたはバッファ済メッセージのみを対象とするように宣言することを要求しません。

Oracle JMSは、JMSMessageIDによる高速で効率的なメッセージのデキュー、メッセージ・ヘッダーのセレクタ、およびメッセージ・プロパティのセレクタをサポートしています。Oracle JMSデキュー・コールは、永続メッセージとバッファ済メッセージの両方をチェックします。

注意:

Oracle JMS永続メッセージには一意のメッセージ識別子があります。Oracle JMSバッファ済メッセージ識別子は、キュー/トピック内でのみ一意です。

同時デキュー・プロセスが同じサブスクライバの同じキューからデキューしている場合は、他のプロセスによってロックされているメッセージがスキップされます。

トランザクションのサポート

バッファ済メッセージがトランザクション・セッションでエンキューされる場合、JMSではそれらに対するトランザクション・サポートが必要となります。Oracle JMSでは、バッファ済メッセージに関連するトランザクション・セッションで次の標準が満たされることが保証されます。

  • 原子性

    Oracle JMSトランザクション内の永続メッセージおよびバッファ済メッセージは、アトミックにコミットまたはロールバックされます。バッファ済メッセージがディスクに書き込まれた場合(LOBに関連するメッセージの場合など)でも、ロールバックによってそれらが削除されます。

  • 一貫性

    永続メッセージ操作およびバッファ済メッセージ操作がトランザクションでインターリーブされる場合、すべてのOracle JMSユーザーは影響を受けるキュー/トピックの一貫性のあるビューを共有します。トランザクションによってエンキューされたすべての永続メッセージおよびバッファ済メッセージは、コミット時に表示できるようになります。プロセスがトランザクションの途中で終了した場合は、永続メッセージおよびバッファ済メッセージの両方が元に戻されます。Oracle JMSユーザーには、トランザクションのすべての永続メッセージおよびバッファ済メッセージが表示されるか、それらのいずれも表示されません。

  • 分離

    トランザクションのバッファ済エンキュー操作は、トランザクションがコミットされるまではオーナー・トランザクションにのみ表示されます。トランザクションがコミットされると、すべてのコンシューマに表示されます。

デキュー・トランザクションによってロックされているメッセージはブラウズできます。

確認メッセージの受信

非トランザクション・セッションの確認メッセージ受信のためのack_modeパラメータには、3つの値が定義されています。

  • DUPS_OK_ACKNOWLEDGE

    このモードでは、重複メッセージが許可されます。

  • AUTO_ACKNOWLEDGE

    このモードでは、セッションはメッセージを自動的に確認します。

  • CLIENT_ACKNOWLEDGE

    このモードでは、メッセージ・プロデューサ確認メソッドをコールすることによって、クライアントはメッセージを明示的に確認します。メッセージを確認すると、以前に処理されたすべてのメッセージが確認されます。

関連項目:

セッションの作成

バッファ済メッセージのサービス品質

JMSは、伝播されていないバッファ済メッセージを最大1回配信することをサポートするようにプロバイダに要求しています。バッファ済メッセージのリカバリが無効にされている場合、Oracle JMSはこの標準を満たしています。

現在のメッセージ伝播の実装では、メッセージの重複配信が行われることがあります。ただし、メッセージの伝播はOracle JMSによって提供される拡張であるため、これはJMS標準に違反しません。

関連項目:

バッファ済メッセージが重複配信される原因については、バッファ済メッセージの伝播を参照してください。

バッファ済メッセージでサポートされるJMSタイプ

Oracle JMSは、JMSで定義されているタイプをOracleのユーザー定義タイプにマップし、JMSメッセージを格納するためにそれらのユーザー定義タイプのキューを作成します。これらのタイプの一部にはLOB属性があり、メッセージが永続またはバッファ済のいずれであってもOracle JMSはディスクに書き込みます。

たとえば、JMSタイプJMSTextMessageのユーザー定義タイプSYS.AQ$_JMS_TEXT_MESSAGEでは、4kより小さいテキスト文字列がVARCHAR2列に格納されます。ただし、4kより大きいテキスト文字列を格納するためのCLOB属性があります。

JMSメッセージは4kより大きい場合がよくあるため、Oracle JMSは大きいメッセージをメモリーに格納できる新しいADTを提供しています。ADTのディスク表示は変わりませんが、いくつかのVARCHAR2/RAW属性では最大100kのサイズのJMSメッセージをメモリーに格納できます。100kより大きいメッセージもバッファ済メッセージとしてパブリッシュできますが、ディスクに書き込まれます。

JMS Point-to-Pointモデル機能

Point-to-Pointモデルでは、クライアントは、1つのポイントから別のポイントへメッセージを交換します。メッセージのプロデューサとコンシューマは、シングル・コンシューマ・キューを使用してメッセージを送受信します。管理者は、AQjmsSessioncreateQueueメソッドを使用して、シングル・コンシューマ・キューを作成します。キューを使用する前に、AQjmsDestinationstartコールを使用して、キューをエンキュー/デキューに対して有効にする必要があります。クライアントは、AQjmsSessiongetQueueメソッドを使用して事前に作成されたキューに対するハンドルを取得します。

シングル・コンシューマ・キューの場合、メッセージは1つのコンシューマが1度のみ処理できます。同じキューから同時にデキューするプロセスまたはオペレーティング・システム・スレッドが複数存在する場合、各プロセスはキューの先頭にあるロックされていない最初のメッセージをデキューします。ロックを作成したプロセス以外のプロセスは、ロックされたメッセージをデキューできません。

処理が済むと、キューの保存期間が0(ゼロ)の場合はそのメッセージは削除され、そうでない場合は指定された期間保存されます。メッセージが保存されている間は、キュー表ビューに対してSQLを使用して問い合せたり、QueueBrowserで処理済メッセージのメッセージ識別子を指定してデキューできます。

QueueSender

クライアントは、QueueSenderを使用して、キューにメッセージを送信します。これは、クライアントのSessionでキューをcreateSenderメソッドに渡すことによって作成されます。また、クライアントにはキューを指定しないで、QueueSenderを作成するオプションがあります。この場合、キューを送信操作のたびに指定する必要があります。

クライアントは、QueueSenderによって送信されたすべてのメッセージのデフォルト配信モード、優先順位およびTimeToLiveを指定できます。または、クライアントはこれらのオプションを各メッセージに対して定義できます。

QueueReceiver

クライアントはQueueReceiverを使用してキューからメッセージを受信します。これは、クライアントのSessioncreateQueueReceiverを使用して作成されます。messageSelectorがあってもなくても作成できます。

QueueBrowser

QueueBrowserを使用すると、クライアントはメッセージを削除しないで、キュー上でメッセージを参照できます。このブラウズ用メソッドは、キュー内のメッセージをスキャンするために使用されるjava.util.Enumerationを戻します。nextElementに対する最初のコールが、キューのスナップショットを取得します。QueueBrowserは、messageSelectorを使用して作成しても、使用せずに作成してもかまいません。

QueueBrowserも、メッセージをスキャン中にオプションでロックできます。これは、メッセージに対するSELECT...for UPDATEコマンドの場合と似ています。これによって、他のコンシューマがスキャン中のメッセージを削除することはなくなります。

MessageSelector

messageSelectorによって、クライアントは、コンシューマに配信されるメッセージをmessageSelector式と一致するメッセージに制限できるようになります。TextMessage型、StreamMessage型、BytesMessage型、ObjectMessage型またはMapMessage型のペイロードを含むキューのmessageSelectorには、次の1つ以上を持つ任意の式を含めることができます。

  • 接頭辞「ID:」が付いたJMSメッセージ識別子

    JMSMessageID ='ID:23452345'
    
  • JMSメッセージ・ヘッダー・フィールドまたはプロパティ

    JMSPriority < 3 AND JMSCorrelationID = 'Fiction'
    
    JMSCorrelationID LIKE 'RE%'
    
  • ユーザー定義のメッセージ・プロパティ

    color IN ('RED', BLUE', 'GREEN') AND price < 30000 
    

AdtMessage型のペイロードを含むキューのmessageSelectorには、次の1つ以上を持つ任意の式を含めることができます。

  • 接頭辞「ID:」なしのメッセージ識別子

    msgid = '23434556566767676'
    
  • 優先順位または相関識別子、あるいはその両方

    priority < 3 AND corrid = 'Fiction'
    
  • メッセージ・ペイロード

    tab.user_data.color = 'GREEN' AND tab.user_data.price < 30000
    

JMSパブリッシュ・サブスクライブ・モデル機能

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

JMSパブリッシュ・サブスクライブの概要

JMSでは、パブリッシャ(出版者)の機能を持つアプリケーションとサブスクライバ(購読者)の役割を果すアプリケーションとの間の柔軟で動的な通信が可能です。アプリケーションが結合されることはなく、メッセージとその内容に基づいて相互に作用します。

メッセージの配信では、パブリッシャ・アプリケーションが明示的にメッセージ受信者を処理または管理する必要はありません。このため、パブリッシャ・アプリケーションの論理を変更しなくても、新しいサブスクライバ・アプリケーションを動的に追加できます。

同様にサブスクライバ・アプリケーションは、メッセージを送信しているパブリッシャ・アプリケーションに関係なく、メッセージの内容に基づいてメッセージを受信します。このため、サブスクライバ・アプリケーションの論理を変更しなくても、新しいパブリッシャ・アプリケーションを動的に追加できます。

サブスクライバ・アプリケーションは、メッセージ・プロパティまたはトピックのメッセージ内容に対してルールベースのサブスクリプション(予約購読)を定義することで、どのようなメッセージに関心があるのかを指定できます。システムは、ルールベースのサブスクリプションを使用して、パブリッシュされたメッセージの受信者を計算し、自動的にルーティングします。

パブリッシュ・サブスクライブ・モデルでは、メッセージはトピックに対してパブリッシュされ、トピックから受信されます。トピックは、AQjmsSessionCreateTopic()メソッドを使用して作成されます。クライアントは、AQjmsSessiongetTopic()メソッドを使用して事前に作成されたトピックに対するハンドルを取得できます。

DurableSubscriber

クライアントはDurableSubscriberを、クライアントのSession内でcreateDurableSubscriber()メソッドを使用して作成します。messageSelectorがあってもなくても作成できます。

messageSelectorによって、クライアントは、サブスクライバに配信されるメッセージをセレクタにマッチするメッセージに制限できます。セレクタ構文の詳細は、Oracle Databaseアドバンスト・キューイングJava APIリファレンスcreateDurableSubscriberに関する項を参照してください。

永続サブスクライバが同じ名前を使用するときのアクションは、実行時にOracle Java Message Service (Oracle JMS)クライアントに設定されるJava EE準拠モードによって異なります。

非準拠モードでは、同じ名前の2つの永続的なTopicSubscriberオブジェクトが、2つの異なるトピックに対してアクティブになることができます。準拠モードでは、複数の永続サブスクライバが同じ名前を持つことは許可されません。同じトピックに対して作成された2つのサブスクライバが同じ名前を使用する場合、各サブスクライバに使用されるセレクタが異なると、DBMS_AQJMS.ALTER_SUBSCRIBER()の内部コールを使用して、基になるOracle Database Advanced Queuingサブスクリプションが変更されます。

2つのサブスクライバが同じ名前を使用し、2つの異なるトピックに対して作成される場合、同じサブスクリプション名を使用するクライアントがそれぞれサブスクリプション名を作成すると、既存のサブスクリプションは削除され新しいサブスクリプションが作成されます。

2つのサブスクライバが同じ名前を使用し、2つの異なるトピックに対して作成される場合、別のクライアント(最初にそのサブスクリプション名を作成したクライアントではない)が既存のサブスクリプション名を使用すると、サブスクリプションは削除されずにエラーが発生します。サブスクリプションがJMSまたはPL/SQLのどちらで作成されたかが不明であるため、その他のトピックについてのサブスクリプションは削除しないでください。

関連項目:

RemoteSubscriber

リモート・サブスクライバは、createRemoteSubscriberコールを使用して定義されます。リモート・サブスクライバは、リモート・トピックでの特定のコンシューマ、またはリモート・トピックでのすべてのサブスクライバになることができます。

リモート・サブスクライバは、AQjmsAgent構造を使用して定義されます。AQjmsAgentは、名前およびアドレスで構成されます。名前は、リモート・トピックのconsumer_nameを参照します。アドレスは、次のようにしてリモート・トピックを参照します。

schema.topic_name[@dblink]

リモート・トピックで特定のコンシューマに対してメッセージをパブリッシュするには、リモート・トピックでの受信者subscription_nameが、AQjmsAgentの名前フィールドに指定されている必要があります。リモート・トピックは、AQjmsAgentのaddressフィールドに指定される必要があります。

リモート・トピックのすべてのサブスクライバに対してメッセージをパブリッシュするには、AQjmsAgentのnameフィールドをNULLに設定する必要があります。リモート・トピックは、AQjmsAgentのaddressフィールドに指定される必要があります。

TopicPublisher

メッセージはTopicPublisherを使用してパブリッシュされます。これは、TopiccreatePublisherメソッドに渡すことによって作成されます。また、クライアントにはTopicを指定しないで、TopicPublisherを作成するオプションがあります。この場合、Topicをパブリッシュ操作のたびに指定する必要があります。クライアントは、TopicPublisherによって送信されるすべてのメッセージのデフォルト配信モード、優先順位およびTimeToLiveを指定できます。また、各メッセージごとに、これらのオプションを指定することもできます。

受信者リスト

JMSパブリッシュ・サブスクライブ・モデルでは、クライアントは、トピックのすべてのサブスクライバにメッセージを送信するのではなく、明示的な受信者リストを指定できます。これらの受信者は、トピックの既存のサブスクライバである場合もあれば、そうでない場合もあります。受信者リストは、このメッセージのトピックのサブスクリプション・リストをオーバーライドします。受信者リスト機能は、JMSに対するOracleの拡張です。

TopicReceiver

受信者名が受信者リストに明示的に指定されていても、その受信者がキューのサブスクライバではない場合、その受信者に送信されるメッセージは、TopicReceiverを作成することによって受信できます。サブスクライバ名が指定されていない場合、クライアントがメッセージを受信するには、リモート・サイトで永続サブスクライバを使用する必要があります。TopicReceiverは、JMSに対するOracleの拡張です。

TopicReceiverは、messageSelectorを使用して作成できます。これによって、クライアントは、受信者に配信されるメッセージをセレクタにマッチするメッセージに制限できます。

関連項目:

MessageSelector

TopicBrowser

TopicBrowserを使用すると、クライアントはメッセージを削除しないでトピック上でメッセージを参照できます。このブラウズ用メソッドは、トピック・メッセージをスキャンするために使用されるjava.util.Enumerationを戻します。TopicBrowserを作成できるのは、永続サブスクライバのみです。nextElementに対する最初のコールが、トピックのスナップショットを取得します。

TopicBrowserは、メッセージをスキャン中にオプションでロックできます。これは、メッセージに対するSELECT...for UPDATEコマンドの場合と類似しています。これによって、他のコンシューマがスキャン中のメッセージを削除することはなくなります。

TopicBrowserは、messageSelectorを使用して作成できます。これによって、クライアントは、コンシューマに配信されるメッセージをセレクタにマッチするメッセージに制限できるようになります。

TopicBrowserは、パージ機能をサポートしています。これによって、TopicBrowserを使用するクライアントは、トピックの現行のブラウズ操作中に参照されたすべてのメッセージを廃棄できます。パージとは、参照済のすべてのメッセージを破壊的に受信することと同じです(TopicSubscriberを使用して削除した場合と似ています)。

パージでは、メッセージがTopicBrowserjava.lang.EnumerationnextElement()操作へのコールを使用してクライアントに戻された場合、そのメッセージは参照済とみなされます。クライアントがまだ参照していないメッセージは、パージ中には廃棄されません。パージ操作は、同じTopicBrowserに対して何度も実行できます。

TopicBrowserの作成に使用したJMS Sessionがコミットされると、パージは正常に実行されます。セッションに対する操作がロールバックされた場合、パージ操作も取り消されます。

JMSパブリッシュ・サブスクライバ操作の設定

JMSでパブリッシュ・サブスクライブ・モデルの通信を使用するステップは、次のとおりです。

  1. メッセージを保持するために1つ以上のトピックを設定します。これらのトピックは、関心がある領域またはサブジェクトを表します。たとえば、トピックで請求済注文情報を表すことができます。
  2. AQjmsDestinationstartコールを使用して、トピックに対するエンキュー/デキューを有効にします。
  3. 永続サブスクライバのセットを作成します。各サブスクライバは、受信を希望するメッセージを選択するmessageSelectorを指定できます。NULLのmessageSelectorは、そのトピックに対してパブリッシュされたすべてのメッセージの受信をサブスクライバが希望していることを示します。

    サブスクライバはローカルでもリモートでもかまいません。ローカル・サブスクライバは、メッセージがパブリッシュされるトピックと同じトピックに対して定義された永続サブスクライバです。リモート・サブスクライバは、特定のキューのサブスクライバとして定義された別のトピックまたはそのトピックに対する受信者です。リモート・サブスクライバを使用するには、ソース・トピックと宛先トピック間の伝播を設定する必要があります。リモート・サブスクライバと伝播は、JMSに対するOracleの拡張です。

    関連項目:

    伝播の管理

  4. パブリッシャのSessioncreatePublisher()メソッドを使用してTopicPublisherオブジェクトを作成します。メッセージは、publishコールを使用してパブリッシュされます。メッセージは、トピックのすべてのサブスクライバ、またはトピックに対する指定された受信者のサブセットに対してパブリッシュできます。
  5. サブスクライバは、receiveメソッドを使用してトピックに関するメッセージを受信します。
  6. サブスクライバは、メッセージ・リスナーを使用して、非同期にメッセージを受信することもできます。

JMSメッセージ・プロデューサの機能

メッセージの優先順位および順序付け

メッセージの順序付けは、メッセージがキューまたはトピックから受信される順序を決定します。キューまたはトピックのキュー表の作成時に順序づけの方式が指定されます。現在は、Oracle Database Advanced Queuingでは、メッセージの優先順位とエンキュー時間に基づいた順序づけをサポートしており、これによって順序づけの方法が4種類あります。

  • First-In, First-Out (FIFO)

    エンキュー時刻が順序付け基準として選択されると、メッセージはエンキュー時刻の順序で受信されます。エンキュー時刻は、メッセージのパブリッシュ/送信時にOracle Database Advanced Queuingによってメッセージに割り当てられます。これはデフォルトの順序付けです。

  • 優先順位による順序付け

    優先順位による順序付けが選択されると、各メッセージに優先順位が割り当てられます。優先順位は、パブリッシュ/送信時にメッセージ・プロデューサによってメッセージ・プロパティとして指定できます。メッセージは、割り当てられた優先順位の順序で受信されます。

  • FIFO優先順位

    FIFO優先順位による順序付けが選択されると、トピックまたはキューは優先順位による順序付けの場合と同様に機能します。2つのメッセージに同じ優先順位が割り当てられた場合、両者はエンキュー時刻の順に受信されます。

  • エンキュー時刻に続く優先順位による順序付け

    同じエンキュー時刻のメッセージは、そのメッセージの優先順位に従って受信されます。2つのメッセージの順序付け基準が同じ場合、受信される順序は予想できません。ただし、1つのセッション中に特定の順序付け基準で生成されたメッセージは、送信された順序で受信されることがOracle Database Advanced Queuingにより保証されます。

永続メッセージに使用できる順序付けスキームはすべて、バッファ済メッセージにも使用できますが、使用できるのは各メッセージ・クラス内のみです。同じセッション内でエンキューまたはパブリッシュされた永続メッセージとバッファ済メッセージ間の順序付けは、現在はサポートされていません。

メッセージ遅延の指定

メッセージをキュー/トピックに対して送信/パブリッシュするときに、遅延を指定できます。遅延は、そのメッセージがメッセージ・コンシューマに対して使用可能になるまでの時間を表します。遅延指定されたメッセージは、遅延の期限が切れるまで待機状態になります。遅延指定は、メッセージ識別子による受信でオーバーライドされます。

遅延は、JMSメッセージ・プロパティに対するOracle Database Advanced Queuingの拡張機能です。Oracle Database Advanced Queuingのバックグラウンド・プロセスのキュー・モニターが起動される必要があります。

メッセージ期限切れの指定

メッセージのプロデューサは、メッセージの期限切れまたはTimeToLiveを指定できます。これによって、そのメッセージがメッセージ・コンシューマに対して使用可能な期間が定義されます。

TimeToLiveは、送信/パブリッシュ時に指定するか、MessageProducerの設定済TimeToLiveメソッドを使用して指定することが可能で、前者が後者よりも優先されます。TimeToLiveを実装するには、Oracle Database Advanced Queuingのバックグラウンド・プロセスのキュー・モニターが実行されている必要があります。

メッセージのグループ化

1つのキューまたはトピックに属するメッセージをグループ化してセットを形成し、一度に1人のユーザーのみによって消費されるように設定できます。そのためには、トランザクション処理によるメッセージのグループ化が可能なキュー表にキューまたはトピックを作成する必要があります。同じグループに属するメッセージはすべて同じトランザクション内に作成する必要があり、同じトランザクション内に作成されたメッセージはすべて同じグループに属します。

メッセージのグループ化は、JMS仕様に対するOracle Database Advanced Queuingの拡張機能です。

この機能を使用すると、複雑なメッセージを、リンクされた一連の単純なメッセージに分割できます。たとえば、請求書キュー宛ての請求書は、ヘッダーのメッセージ、詳細情報の複数のメッセージ、フッターのメッセージの順に分割できます。

小さいオブジェクトに分割できるイメージやビデオなどの複合ラージ・オブジェクトがメッセージ・ペイロードにある場合は、メッセージのグループ化が非常に有効です。

グループに含まれるメッセージの優先順位、遅延および期限切れの各プロパティは、単にグループの最初のメッセージ(ヘッダー)のプロパティによってのみ判断されます。グループの他のメッセージのプロパティは無視されます。

メッセージ・グループは、伝播中も保持されます。宛先トピックは、トランザクション処理のグループ化に対して使用可能にしておく必要があります。

関連項目:

トランザクション処理でグループ化可能なキューからメッセージをデキューするときにメッセージ・グループを保持する場合、注意する必要がある制限については、「デキュー機能」を参照してください。

JMSメッセージ・コンシューマ機能

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

メッセージの受信

JMSアプリケーションは、メッセージ・コンシューマを作成することによって、メッセージを受信できます。メッセージは、receiveコールを使用して同期的に受信するか、メッセージ・リスナーを使用して非同期的に受信できます。

受信モードには次の3つがあります。

  • メッセージがコンシューマに届くまでブロック

  • 指定最大時間までブロック

  • 非ブロック

受信におけるメッセージのナビゲーション

コンシューマがナビゲーション・モードを指定しない場合、セッションの最初のreceiveはキューまたはトピックの最初のメッセージを取り出し、第2のreceiveは次のメッセージを取得します。優先順位が高いメッセージがコンシューマに届く場合、すでに届いているメッセージを削除するまで、コンシューマはこのメッセージを受信しません。

コンシューマが、メッセージに対してより効率的にキューのナビゲーションを制御できるように、Oracle Database Advanced QueuingにはJMS拡張機能として複数のナビゲーション・モードが用意されています。これらのモードは、TopicSubscriberQueueReceiverまたはTopicReceiverで設定できます。

グループ化されていないメッセージには、次の2つのモードを使用できます。

  • FIRST_MESSAGE

    このモードでは、位置がキューの先頭にリセットされます。コンシューマがキューの最上位にあるメッセージを削除できるため、優先順位に基づくキューで役立ちます。

  • NEXT_MESSAGE

    このモードは、コンシューマの確立された位置の後のメッセージを取得します。たとえば、4番目のメッセージの位置で適用されたNEXT_MESSAGEは、そのキューの5番目のメッセージを取得します。これはデフォルト・アクションです。

グループ化メッセージには、次の3つのモードを使用できます。

  • FIRST_MESSAGE

    このモードでは、位置がキューの先頭にリセットされます。

  • NEXT_MESSAGE

    このモードでは、位置が同一トランザクションの次のメッセージに設定されます。

  • NEXT_TRANSACTION

    このモードでは、位置が次のトランザクションの最初のメッセージに設定されます。

注意:

シャード・キューは、前述の3つのモードをサポートしていません。

次の方法でメッセージが受信される場合、グループ化トランザクションのプロパティを無効にできます。

  • セレクタに相関識別子を指定して受信

  • セレクタにメッセージ識別子を指定して受信

  • トランザクション・グループのメッセージがすべて受信される前にコミット

NEXT_MESSAGEまたはNEXT_TRANSACTIONオプションの使用中にコンシューマがキューの最後に到達したとします。ブロッキングreceive()を指定していた場合は、ナビゲート位置は自動的にそのキューの先頭に変更されます。

デフォルトでは、QueueReceiverTopicReceiverまたはTopicSubscriberは、最初のreceiveコールにFIRST_MESSAGEを、以降のreceive()コールにNEXT_MESSAGEを使用します。

メッセージのブラウズ

デキューするクライアントがキューからメッセージを削除できる通常のreceiveの他に、JMSでは、JMSクライアントがキューで自身のメッセージをブラウズできるようにするインタフェースを提供しています。QueueBrowserは、QueueSessionからcreateBrowserメソッドを使用して作成できます。

メッセージが参照されると、そのメッセージは引き続き処理できます。メッセージがブラウズされた後は、同時セッションからreceiveコールがそのメッセージを削除する場合があるため、JMSセッションに引き続き使用できるとはかぎりません。

一度参照したメッセージが同時JMSクライアントによって削除されないようにするために、ロック・モードでメッセージを参照できます。そのためには、JMSインタフェースに対するOracle Database Advanced Queuingの拡張機能を使用して、ロック・モードを持つQueueBrowserを作成する必要があります。メッセージのロックは、セッションがコミットまたはロールバックを実行すると解放されます。

QueueBrowserによって参照されたメッセージを削除するには、セッションがQueueReceiverを作成し、JMSmesssageIDをセレクタとして使用する必要があります。

取出しを伴わないメッセージの削除

コンシューマは、receiveNoDataコールを使用してキューまたはトピックからメッセージを取得することなく、メッセージを削除できます。アプリケーションがQueueBrowserなどを使用してメッセージをすでに確認した場合に役立ちます。このモードを使用すると、JMSクライアントがペイロードをデータベースから取得するオーバーヘッドを回避できます(メッセージが大きい場合、オーバーヘッドが顕著である可能性があります)。

遅延間隔をおいた後の再試行

キュー/トピックからメッセージを受信するトランザクションが失敗した場合、そのメッセージを削除する試行に失敗したとみなされます。Oracle Database Advanced Queuingは、メッセージ削除の試行に失敗した回数をメッセージ履歴に記録します。

アプリケーションでは、メッセージに対する再試行の最大回数をキュー/トピック・レベルで指定できます。メッセージ削除がこの数より多く失敗した場合、メッセージは例外キューに移動されます。

Oracle Database Advanced Queuingでは、ユーザーはmax_retriesとともにretry_delayも指定できます。これは、受信の試行に失敗したメッセージを、retry_delay間隔後に引き続きキューで参照し、デキューできることを意味します。それまでこのメッセージはWAITING状態になります。Oracle Database Advanced Queuingのバックグラウンド・プロセスのタイム・マネージャは、再試行遅延プロパティを強制的に適用します。

再試行の最大回数および再試行の遅延は、キュー/トピックのプロパティです。このプロパティは、キュー/トピックの作成時、またはキュー/トピックに対する変更メソッドを使用して設定できます。MAX_RETRIESのデフォルト値は5です。

注意:

シャード・キューは、再試行の遅延をサポートしていません。

MessageListenerを使用したメッセージの非同期受信

JMSクライアントは、setMessageListenerメソッドを使用してMessageListenerを設定することによって、メッセージを非同期的に受信できます。

コンシューマにメッセージが届いた場合、メッセージ・リスナーのonMessageメソッドがそのメッセージで起動されます。メッセージ・リスナーは、メッセージの受信をコミットまたは異常終了できます。メッセージ・リスナーは、JMS Connectionが停止されている場合、メッセージを受信しません。一度メッセージ・リスナーがコンシューマに対して設定されると、メッセージの受信にreceiveコールを使用することはできません。

JMSクライアントは、セッションでMessageListenerを設定することによって、そのセッションのすべてのコンシューマに対してメッセージを非同期的に受信できます。一度メッセージ・リスナーが設定されると、そのセッションでは、その他のメッセージ受信モードを使用できません。

例外キュー

例外キューは、すべての期限切れのメッセージまたは使用できないメッセージが格納されるリポジトリです。アプリケーションがメッセージを例外キューに直接エンキューすることはできません。ただし、期限切れまたは処理できないメッセージを処理するアプリケーションは、例外キューからこれらのメッセージを受信または削除できます。

例外キューからメッセージを取り出すには、JMSクライアントはPoint-to-Pointインタフェースを使用する必要があります。トピック用のメッセージの例外キューは、使用可能な複数のコンシューマでキュー表に作成する必要があります。他のキューと同様に、例外キューもAQOracleQueueクラスでstartメソッドを使用して、メッセージを受信できる必要があります。例外キューをエンキュー可能に設定しようとすると、例外が発生します。

シャード・キューは、DBMS_AQADM.CREATE_EXCEPTION_QUEUE APIを介して例外キューをサポートするようになりました。

  PROCEDURE CREATE_EXCEPTION_QUEUE(
    sharded_queue_name     IN VARCHAR2,
    exception_queue_name   IN VARCHAR2 DEFAULT NULL,
    multiple_consumers     IN BOOLEAN DEFAULT FALSE,
    storage_clause         IN VARCHAR2 DEFAULT NULL,
    sort_list              IN VARCHAR DEFAULT NULL,
    comment                IN VARCHAR2 DEFAULT NULL
    );

例外キューは、"JMS_OracleExcpQ"と呼ばれるOracle固有のメッセージ・プロパティで、メッセージの送信/パブリッシュ前に設定できます。例外キューが指定されていないと、デフォルトの例外キューが使用されます。非シャード・キューの場合、デフォルトの例外キューはキュー表の作成時に自動的に作成され、AQ$_queue_table_name_Eと命名されます。デフォルトでは、シャード・キューには例外キューは作成されません。

メッセージは、次の条件が成立するときに例外キューに移されます。

  • そのメッセージが、指定されたtimeToLive内にデキューされなかった場合。

    複数のサブスクライバを指定したメッセージの場合、指定されたtimeToLive内にそのメッセージをデキューできない受信者が1つ以上あると、メッセージは例外キューに移されます。

  • メッセージが正常に受信されたが、メッセージ処理中のエラーのためアプリケーションがreceiveを実行したトランザクションを異常終了した場合。そのメッセージはキュー/トピックに戻され、メッセージ受信のために待機中のどのアプリケーションでも使用可能になります。

    アプリケーションがトランザクション全体を異常終了するか、receive前のセーブポイントまでロールバックしたときは、receiveがロールバックまたはUNDOされたとみなされます。

    これは失敗したメッセージ受信の試行であるため、その再試行回数は更新されます。メッセージの再試行回数が、メッセージが常駐するキュー/トピックに指定された最大値を超える場合、そのメッセージは例外キューに移されます。

    メッセージが複数のサブスクライバを持つ場合、そのメッセージは、すべての受信者が再試行制限を超えたときにのみ、例外キューに移されます。

注意:

サーバー・プロセスがインスタンスで停止した(ALTER SYSTEM KILL SESSIONまたはSHUTDOWN ABORTなど)ためにデキュー・トランザクションが失敗した場合、RETRY_COUNTは増分されません。

JMS伝播

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

注意:

シャード・キューは、RemoteSubscriber、伝播のスケジューリング、拡張伝播スケジュール機能および伝播中の例外処理をサポートしていません。

RemoteSubscriber

Oracle Database Advanced Queuingによって、他のデータベースにあるサブスクライバをトピックにサブスクライブできます。トピックに対してパブリッシュされたメッセージがリモート・サブスクライバの基準を満たしている場合は、リモート・サブスクライバに指定されているリモート・データベースにあるキュー/トピックに自動的に伝播します。伝播は、データベース・リンクおよびOracle Net Servicesを使用して実行されます。これによって、同じデータベースに接続しなくても、アプリケーション同士が互いに通信できます。

リモート・サブスクライバを実装するには、次の2つの方法があります。

  • createRemoteSubscriberメソッドは、トピック上またはトピックに対してリモート・サブスクライバを作成するために使用します。このリモート・サブスクライバは、クラスAQjmsAgentのインスタンスとして指定されます。

  • AQjmsAgentには、名前およびアドレスがあります。アドレスは、キュー/トピックおよびサブスクライバのデータベースへのデータベース・リンクで構成されています。

リモート・サブスクライバには、次の2種類があります。

  • リモート・サブスクライバがトピックである場合。

    これは、AQjmsAgentオブジェクトのリモート・サブスクライバに名前が指定されず、アドレスがトピックである場合に発生します。サブスクライバのサブスクリプションを満たすメッセージが、リモート・トピックに伝播されます。伝播されたメッセージは、それが満たすリモート・トピックのすべてのサブスクリプションに対して使用可能になります。

  • メッセージに対して特定のリモート受信者を指定する場合。

    リモート・サブスクリプションは、リモート・データベースにある特定のコンシューマに対して指定できます。リモート受信者の名前が(AQjmsAgentオブジェクトに)指定される場合、サブスクリプションを満たすメッセージが、その受信者専用のリモート・データベースに伝播されます。リモート・データベースにある受信者は、TopicReceiverインタフェースを使用してメッセージを取り出します。リモート・サブスクリプションは、Point-to-Pointキューに対して指定することもできます。

伝播スケジュール

伝播は、メッセージがターゲットの接続先データベースに伝播されるすべてのトピックについて、schedule_propagationメソッドを使用してスケジューリングされる必要があります。

スケジュールは時間の枠を示し、メッセージはその枠内でソース・トピックから伝播されます。この時間枠は、ネットワーク通信量、ソース・データベースの負荷、接続先データベースの負荷などの複数の要因に左右されます。したがって、スケジュールは特定のソースおよび宛先にあわせて調整する必要があります。スケジュールが作成されると、ジョブは自動的にjob_queue機能に発行され、伝播が処理されます。

伝播スケジュールのための運用管理コールによって、スケジュール管理を柔軟に行うことができます。あるスケジュールの存続時間または伝播枠パラメータによって、伝播が開始される時間枠が指定されます。存続時間が指定されない場合、時間枠は無制限の単一枠になります。枠を定期的に繰り返す必要がある場合、連続する枠の間の周期的間隔を定義するnext_time機能を使用して有限の存続時間を指定します。

あるキューに定義された伝播スケジュールは、そのキューの有効期間中いつでも変更または削除できます。さらに、(スケジュールを削除するかわりに)一時的に使用不可にするコール、および使用不可のスケジュールを使用可能にするコールがあります。メッセージがスケジュール内で伝播されているとき、そのスケジュールはアクティブです。すべての管理コールは、スケジュールがアクティブかどうかに関係なく実行されます。スケジュールがアクティブの場合、コールが実行されるまでに数秒かかります。

伝播が開始されるには、ジョブ・キュー・プロセスを起動する必要があります。少なくとも2つのジョブ・キュー・プロセスを起動する必要があります。接続先データベースへのデータベース・リンクも有効にする必要があります。伝播のソースおよび宛先トピックは、同じメッセージ型である必要があります。リモート・トピックは、エンキューできる必要があります。データベース・リンクのユーザーもリモート・トピックに対するエンキュー権限を持つ必要があります。

拡張伝播スケジュール機能

伝播のために定義されたカタログ・ビューは、アクティブ・スケジュールに関する次の情報を提供します。

  • そのスケジュールを処理しているバックグラウンド・プロセスの名前

  • 伝播を処理しているセッションのSID(セッションおよびシリアル番号)

  • スケジュールを処理しているインスタンス(Oracle RACを使用している場合)

  • 先行して正常に実行されたスケジュール

  • 次に実行予定のスケジュール

スケジュールごとに次の伝播統計が保持され、キュー管理者がスケジュール調整に役立てることができます。

  • スケジュールの中で伝播されたメッセージ合計数

  • スケジュールの中で伝播されたバイト合計数

  • 伝播枠の中で伝播されたメッセージの最大数

  • 伝播枠の中で伝播されたバイトの最大値

  • 伝播枠の中で伝播されたメッセージの平均数

  • 伝播済メッセージの平均サイズ

  • 伝播済メッセージの平均時間

伝播機能には、障害対処およびエラー・レポートが組み込まれています。たとえば、指定されたデータベース・リンクが無効な場合、リモート・データベースが使用できない場合、またはリモート・トピック/キューにエンキューできない場合、適切なエラー・メッセージがレポートされます。伝播は指数バックオフ・スキームを使用して、障害が発生したスケジュールからの伝播を再試行します。あるスケジュールで続けて障害が発生したときは、最初の再試行は30秒後、次の再試行は60秒後、3回目の再試行は120秒後、というように続きます。再試行時間が現行の伝播枠の期限切れ時刻を超える場合は、次の再試行は、次の伝播枠の開始時刻に行われます。最大16回の再試行が行われた後、そのスケジュールは自動的に使用不可能になります。

注意:

再試行が次の伝播ウィンドウに移動されると、常に移動されるようになり、指数バックオフ・スキームは再試行のスケジュールを管理しません。DBMS_AQADM.SCHEDULE_PROPAGATION()next_timeパラメータで指定された日付関数の結果、ウィンドウ間の間隔が短くなると、再試行の失敗数はすぐに16に達し、スケジュールが無効になります。

障害のためにスケジュールが自動的に使用不可になると、関連情報がアラート・ログに書き込まれます。スケジュールで失敗が発生したか、その場合は何回連続して失敗が発生したか、失敗の原因を示すエラー・メッセージ、および最後の失敗が発生した時刻を、いつでも確認できます。この情報を調べることで、管理者は障害を回復し、スケジュールを使用可能にできます。

再試行の間に伝播が成功したときは、障害の数は0(ゼロ)にリセットされます。

伝播機能にはOracle Real Application Clustersサポートが組み込まれていますが、ユーザーおよび管理者には透過的です。伝播を処理するジョブは、ソース・トピックが常駐しているキュー表の所有者と同じインスタンスに送られます。あるインスタンスに障害が発生してトピックを保存しているキュー表が他のインスタンスに移される場合は、伝播ジョブも必ず自動的に新しいインスタンスに移行されます。これによって、インスタンス間のping操作は最小限に抑えられ、パフォーマンスが向上します。伝播は、同時スケジュールをいくつでも処理できるように設計されています。

job_queue_processesの最大数は1000で、その一部は伝播に関連しないジョブの処理に使用できます。このために、伝播にはマルチタスキングおよびロード・バランシングのサポートが組み込まれています。伝播アルゴリズムは、複数スケジュールが単一スナップショット(job_queue)のプロセスによって処理できるように設計されています。job_queueプロセスに対する伝播の負荷は、異なるソース・トピックからのメッセージ到着の割合に基づいて偏りが発生する場合があります。あるプロセスが数個のアクティブ・スケジュールによって過負荷になっている一方で、別のプロセスは受動的なスケジュールが多いために余力があるというとき、伝播はプロセス間で負荷が均等になるようにスケジュールを自動的に再分配します。

伝播中の例外処理

ネットワーク障害のようなシステム・エラーが発生した場合、Oracle Database Advanced Queuingは指数バックオフ・アルゴリズムを使用してメッセージを伝播する試みを継続します。キューからデータベース・リンクへの伝播中のアプリケーション・エラーを示している状況では、Oracle Database Advanced QueuingはそのメッセージにUNDELIVERABLEというマークを付けてalert.logに記録します。このようなエラーは、リモート・キューが存在しない場合、またはソース・キューおよびリモート・キューの型が一致しない場合に発生します。background_dump_destディレクトリのトレース・ファイルには、そのエラーに関する追加情報があります。

新規のジョブ・キュー・プロセスが開始すると、型を再検証できるように型の不一致エラーを消去します。ジョブ・キュー・プロセス数に上限を設定して、伝播のビジー状態が続く場合、ジョブ・キュー・プロセスが終了して再開するまで待つ必要はありません。キューの型は、必要に応じてDBMS_AQADM.VERIFY_QUEUE_TYPESを使用して再検証できます。

注意:

キューからキューへの伝播中に型の不一致が検出されると、伝播は停止してエラーが発生します。このような場合は、DBA_SCHEDULESビューを問い合せて、特定の宛先への伝播中に発生した最後のエラーを判断する必要があります。このメッセージには、UNDELIVERABLEマークは付いていません。

JMS AQのメッセージ変換

あるフォーマットのメッセージを別のフォーマットのメッセージにマップするために変換を定義できます。変換は、同一の情報を異なるフォーマットで表現するアプリケーションを統合する必要がある場合に有効です。変換はSQL式およびPL/SQLファンクションです。メッセージ変換は、標準JMSインタフェースに対するOracle Database Advanced Queuingの拡張機能です。

変換は、DBMS_TRANSFORM.create_transformationプロシージャを使用して作成できます。変換は、次の操作を行う場合に指定できます。

  • キューまたはトピックへのメッセージの送信

  • キューまたはトピックからのメッセージの受信。

  • TopicSubscriberの作成

  • RemoteSubscriberの作成。これによって、異なるフォーマットのトピック間でメッセージを伝播できます。

注意:

JMSシャード・キューは、メッセージ変換をサポートしていません。

JMSストリーミング

AQ JMSは、大量のメッセージ・データまたはペイロードを送受信するアプリケーション用に、AQjmsBytesMessageおよびAQjmsStreamMessageを介した共有キューのエンキューおよびデキューでのストリーミングをサポートします。

JMSストリーミングは、大きい連続したバイトの配列を送受信するのではなく、メッセージ・ペイロードを小さいチャンクに分割することにより、大きいメッセージを扱うときのメモリー要件を緩和します。JMS標準にストリーミング・メカニズムは含まれないため、AQ JMSはAQストリーミング・エンキューおよびデキュー機能を示すための固有のインタフェースを提供します。これにより、ユーザーは既存のjava入出力ストリームを使用してメッセージ・データまたはペイロードを簡単に送受信できます。

データベースのRDBMS 12.2へのアップグレード時に既存のアプリケーションが変更なしで動作できるように、デフォルトではストリーミングAPIは無効化されます。

クライアント・アプリケーションはシステム・プロパティoracle.jms.useJmsStreamingtrueに設定して使用することにより、JMSストリーミングを有効化できます。

注意:

JMSストリーミングはThinドライバの場合のみサポートされます。

エンキューでのJMSストリーミング

AQ JMSではAQjmsBytesMessageおよびAQjmsStreamMessageの新しいAPI setInputStream(java.io.InputStream)が提供され、メッセージ・データ用の入力ストリームを設定します。

    /**
     * @param inputStream - InputStream to read the message payload
     * @throws JMSException - if the JMS provided fails to read the payload due to
     *                        some internal error
     */
    public void setInputStream(InputStream inputStream) throws JMSException

次のコード・スニペットでは、AQjmsBytesMessageタイプのメッセージが作成され、メッセージ・データ用のFileInputStreamが設定されます。

    Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
    Destination destination = session.createQueue("queueName");
    MessageProducer producer = session.createProducer(destination);
 
     AQjmsBytesMessage bytesMessage = (AQjmsBytesMessage)session.createBytesMessage();
     InputStream input = new FileInputStream("somefile.data");
     bytesMessage.setInputStream(input);
     producer.send(bytesMessage);

注意:

  • BytesMessageおよびStreamMessageのメソッドはjava.io.DataInputStreamおよびjava.io.DataOutputStreamで検出されるメソッドに基づいているため、様々なread*()およびwrite*()メソッドの意味のある変換はストリームでは不可能です。次の使用例では例外が発生します。

    • bytesMessage.setInputStream(input);

      bytesMessage.writeInt(99);

    • bytesMessage.writeInt(99);

      bytesMessage.setInputStream(input);

  • 通常のエンキュー操作と同様に、ストリーミングを使用したエンキューは同期操作となり、エンキューが完了した後でのみ、制御がクライアントに戻されます。

  • これらのAPIが明示的にクライアントにより使用される場合にのみ、ストリーミングがエンキューで使用されます。AQ JMSはメッセージ・データのサイズと関係なく、通常のエンキューではストリーミングを使用しません。

デキューでのJMSストリーミング

ストリーミングを使用したデキュー操作は、2つのステップで実行されます。サーバーでは、メッセージ本文のサイズに基づき、メッセージ本文をストリーミングするかどうかが決定されます。デフォルトのしきい値制限は10MBです。そのため、メッセージ本文が10MBよりも大きく、システム・プロパティoracle.jms.useJmsStreamingを使用して、ストリーミングがクライアントで有効な場合、サーバーはデキューでストリーミングを使用します。

  • これはクライアントがreceive()メソッドを呼び出す場合の通常のデキュー・プロセスです。

    Destination destination = session.createQueue ("queueName");             
    AQjmsConsumer consumer = (AQjmsConsumer) session.createConsumer(destination);             
    Message message = consumer.receive(10000);
    
  • クライアントがペイロードなしのメッセージを受信する場合、クライアントは受信メッセージでのisLargeBody()の呼び出しにより、ストリーミングがデキューで使用されるかどうかを特定します。

      /**
       * This method can be used by the client applications to check whether the message
       * contains large messaege body and hence requires streaming with dequeue.
       * 
       * @return true when the message body is large and server decides to stream
       *         the payload with dequeue
       */
      public boolean isLargeBody() 
    

    isLargeBody()により戻されたtrueの値は、デキューでのストリーミングを示します。デキューでストリーミングを使用する場合、AQ JMSはAQjmsStreamMessageAQjmsBytesMessageに対して正確にメッセージ本文の長さを移入します。そのため、クライアント・アプリケーションはメッセージでgetBodyLength()を呼び出し、ペイロードのサイズを判断できます。

     public long getBodyLength()
    

クライアントがデキューでのストリーミングについて理解したら、受信メッセージで次のAPIのいずれかを使用してメッセージ・データをフェッチできます。

クライアント・アプリケーションは、AQjmsBytesMessageおよびAQjmsStreamMessageで使用可能な次のAPIを使用して、メッセージ・データを受信できます。

 /**
     * Writes the message body to the OutputStream specified.
     * 
     * @param outputStream - the OutputStream to which message body can be written
     * @return the OutputStream containing the message body.
     * @throws JMSException - if the JMS provided fails to receive the message body 
     *                        due to some internal error
     */
    public OutputStream getBody(OutputStream outputStream) throws JMSException
 
    /**
     * Writes the message body to the OutputStream specified, with chunkSize bytes 
     * written at a time.
     * 
     * @param outputStream - the OutputStream to which message body can be written
     * @param chunkSize - the number of bytes to be written at a time, default value 
     *                    8192 (ie. 8KB)
     * @return the OutputStream containing the message body.
     * @throws JMSException - if the JMS provided fails to receive the message body 
     *                        due to some internal error
     */
    public OutputStream getBody(OutputStream outputStream, int chunkSize)throws JMSException
    
 
    /**
     * Writes the message body to the OutputStream specified. This method waits until 
     * the message body is written completely to the OutputStream or the timeout expires.
     * 
     * A timeout of zero never expires, and a timeout of negative value is ignored.
     * 
     * @param outputStream - the OutputStream to which message body can be written
     * @param timeout - the timeout value (in milliseconds)
     * @return the OutputStream containing the message body.
     * @throws JMSException - if the JMS provided fails to receive the message body 
     *                        due to some internal error
     */   
    public OutputStream getBody(OutputStream outputStream, long timeout) throws JMSException 
 
 
    /**
     * Writes the message body to the OutputStream specified, chunkSize bytes at a time. 
     * This method waits until the message body is written completely to the OutputStream
     * or the timeout expires.
     * 
     * A timeout of zero never expires, and a timeout of negative value is ignored.
     * 
     * @param outputStream - the OutputStream to which message body can be written
     * @param chunkSize - the number of bytes to be written at a time, 
     *                    default value 8192 (ie. 8KB)
     * @param timeout - the timeout value (in milliseconds)
     * @return the OutputStream containing the message body.
     * @throws JMSException - if the JMS provided fails to receive the message body 
     *                        due to some internal error
     */   
    public OutputStream getBody(OutputStream outputStream, int chunkSize, long timeout) throws JMSException

次のコード・スニペットは、ストリーミングがデキューで使用され、受信したペイロードがFileOutputStreamに書き込まれるかどうかをチェックします。

     if (message instanceof BytesMessage && (AQjmsBytesMessage)message.isLargeBody()){
         // optional : check the size of the payload and take appropriate action before 
         // receiving the payload.
          (AQjmsBytesMessage) message.getBody(new FileOutputStream(new File("…")));
     } else {
          // normal dequeue
     }

通常、両方のステップが完了すると、メッセージは完全に消費されたとみなされます。AQサーバーにより、ステップ1の後でメッセージでのロックは保持され、ステップ2の後でのみ解除されます。

メッセージ・コンシューマによりメッセージが部分的に消費されることにより発生する可能性のある問題を考慮して、確認モードCLIENT_ACKNOWLEDGEおよびSESSION_TRANSACTEDでのセッション用のストリーミングAPIは制限されました。

そのため、部分的に消費されたメッセージを含む、すべてのメッセージは、次の時点で完全に消費されたとみなされます。

  • message.acknowledge()CLIENT_ACKNOWLEDGEセッションで呼び出されます。

  • セッションのcommit()はトランザクション・セッションで呼び出されます。

通常の場合、セッションrollback()は、そのセッションで受信したメッセージをロールバックします。

JMSストリーミングは使用可能ですが、次の制限があります。

  • ストリーミングはデフォルトで無効化されており、システム・プロパティoracle.jms.useJmsStreamingを使用してクライアント・アプリケーションにより有効化できる

  • メッセージ・データのサイズがしきい値よりも大きい場合に、デキューでストリーミングが使用されます。デフォルトのしきい値は10MBです。

  • ストリーミング・サポートはAQjmsBytesMessageおよびAQjmsStreamMessageで使用可能

  • ストリーミング・サポートは共有キューでのみ使用可能

  • ストリーミング・サポートはThinドライバでのみ使用可能

  • ストリーミング・サポートは、メッセージ・プロデューサがメッセージ配信モードにNON_PERSISTENTを使用しているときは使用できない

  • ストリーミングはメッセージ・リスナーではサポートされません。そのため、MessageConsumerにメッセージ・リスナー・セットがある場合、およびメッセージ・データがしきい値制限を超えている場合は、内部的に通常のデキューが使用されます。

  • ストリーミング・サポートは、確認モードCLIENT_ACKNOWLEDGEおよびSESSION_TRANSACTEDを使用してセッションで使用可能です。

Java EEの準拠

Oracle JMSは、Oracle Sun Microsystems JMS 1.1標準に準拠しています。実行時に、Oracle Java Message Service (Oracle JMS)クライアントに対してJava EE準拠モードを定義できます。準拠モードにするには、コマンドライン・オプションとしてJavaプロパティ oracle.jms.j2eeCompliantTRUEに設定します。非準拠モードにする場合は何もしません。FALSEがデフォルト値です。

Java EE準拠をサポートし、非準拠モードでも使用できるOracle Database Advanced Queuingの機能は次のとおりです。

  • 非トランザクション・セッション

  • 永続サブスクライバ

  • 一時キューおよびトピック

  • 非永続配信モード

  • AQ$_JMS_MESSAGE型のOracle Database Advanced Queuingキューを使用した単一のJMSキューまたはトピックに対する複数のJMSメッセージ・タイプ

  • 永続サブスクライバに対するnoLocalオプション

  • JMSシャード・キューはJMSでネイティブにサポートされており、Java EEコンプライアンスに準拠しています

関連項目:

  • 『Java Message Service Specification』、バージョン1.1、2002年3月18日、Sun Microsystems, Inc.

  • JMSPriorityおよびJMSExpirationに対するJavaプロパティoracle.jms.j2eeCompliantの影響の詳細は、「JMSメッセージ・ヘッダー」を参照してください。

  • 永続サブスクライバに対するJavaプロパティoracle.jms.j2eeCompliantの影響の詳細は、「DurableSubscriber」を参照してください。