10 XStream Inの管理

XStream In構成を管理できます。

この章では、インバウンド・サーバーでのルール、ルール・セットまたはルールベースの変換の使用については扱いません。デフォルトでは、インバウンド・サーバーはルールまたはルール・セットを使用しません。したがって、インバウンド・サーバーは、XStreamクライアント・アプリケーションにより送信された論理変更レコード(LCR)をすべて適用します。ただし、インバウンド・サーバーに送信されたLCRをフィルタリングするために、DBMS_XSTREAM_ADMパッケージとDBMS_RULE_ADMパッケージを使用して、ルールおよびルール・セットをインバウンド・サーバーに追加できます。DBMS_XSTREAM_ADMパッケージを使用してルールベースの変換を指定することもできます。

関連項目:

ルール、ルール・セットおよびルールベースの変換の使用の詳細は、Oracle Streams概要および管理を参照してください

10.1 XStream Inの管理について

XStream In構成の一部であるインバウンド・サーバーなどのデータベース・コンポーネントを変更できます。

XStream Inデータベース・コンポーネントを管理するためのメイン・インタフェースはPL/SQLです。具体的には、オラクル社が提供する次のPL/SQLパッケージを使用してXStream Inを管理します。

10.2 インバウンド・サーバーの起動

XStreamクライアント・アプリケーションから論理変更レコード(LCR)を受信し、LCRを適用するには、インバウンド・サーバーを有効にする必要があります。既存のインバウンド・サーバーを起動するには、DBMS_APPLY_ADMパッケージのSTART_APPLYプロシージャを実行します。

インバウンド・サーバーを起動するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_APPLY_ADMパッケージのSTART_APPLYプロシージャを実行して、apply_nameパラメータにインバウンド・サーバーを指定します。

次の例では、xinという名前のインバウンド・サーバーが起動します。

例10-1 xoutという名前のインバウンド・サーバーの起動

BEGIN
  DBMS_APPLY_ADM.START_APPLY(
    apply_name => 'xin');
END;
/

関連項目:

Oracle Enterprise Manager Cloud Controlを使用して適用プロセスまたはインバウンド・サーバーを起動する手順については、Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照

10.3 インバウンド・サーバーの停止

既存のインバウンド・サーバーを停止するには、DBMS_APPLY_ADMパッケージのSTOP_APPLYプロシージャを実行します。XStream構成内の問題のトラブルシューティングを行う際に、インバウンド・サーバーを停止することがあります。

インバウンド・サーバーを停止するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_APPLY_ADMパッケージのSTOP_APPLYプロシージャを実行して、apply_nameパラメータにインバウンド・サーバーを指定します。

次の例では、xinという名前のインバウンド・サーバーが停止します。

例10-2 xoutという名前のインバウンド・サーバーの停止

BEGIN
  DBMS_APPLY_ADM.STOP_APPLY(
    apply_name => 'xin');
END;
/

関連項目:

Oracle Enterprise Manager Cloud Controlを使用して適用プロセスまたはインバウンド・サーバーを停止する手順については、Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照

10.4 インバウンド・サーバーの適用パラメータの設定

適用パラメータによって、インバウンド・サーバーの動作方法を制御します。インバウンド・サーバーの適用パラメータを設定するには、DBMS_XSTREAM_ADMパッケージのSET_PARAMETERプロシージャを使用します。

インバウンド・サーバーの適用パラメータを設定するには、次のようにします。

  1. アウトバウンド・サーバー・データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_XSTREAM_ADMパッケージのSET_PARAMETERプロシージャを実行して、次のパラメータを指定します。

    • streams_name: インバウンド・サーバーの名前を指定します。

    • streams_type: applyを指定します。

    • parameter: 適用パラメータの名前を指定します。

    • value: 適用パラメータの値を指定します。

次の例では、xinという名前のインバウンド・サーバーのparallelismパラメータが4に設定されます。

例10-3 インバウンド・サーバー・パラメータの設定

BEGIN
  DBMS_XSTREAM_ADM.SET_PARAMETER(
    streams_name => 'xin',
    streams_type => 'apply',
    parameter    => 'parallelism',
    value        => '4');
END;
/

注意:

  • valueパラメータは、パラメータ値が数値の場合にも、常にVARCHAR2値として入力されます。

  • valueパラメータがNULLに設定されているか、または指定されていない場合、パラメータはデフォルト値に設定されます。

関連項目:

10.5 インバウンド・サーバーの適用ユーザーの変更

インバウンド・サーバーではその適用ユーザーのセキュリティ・ドメイン内にLCRが適用され、クライアント・アプリケーションは適用ユーザーとしてインバウンド・サーバーに連結する必要があります。DBMS_XSTREAM_ADMパッケージのALTER_INBOUNDプロシージャを使用して、インバウンド・サーバーの適用ユーザーを変更できます。

クライアント・アプリケーションがインバウンド・サーバーに異なるユーザーとして接続する必要がある場合、または異なるユーザーに関連付けられている権限を使用して変更を適用する場合に、適用ユーザーを変更できます。適用ユーザーに必須権限が付与されていることを確認してください。

関連項目:

適用ユーザーに必要な権限の詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照

インバウンド・サーバーの適用ユーザーを変更するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。

    XStream管理者は、インバウンド・サーバーの適用ユーザーを変更するにはDBAロールが付与されている必要があります。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_XSTREAM_ADMパッケージのALTER_INBOUNDプロシージャを実行して、次のパラメータを指定します。

    • server_name - インバウンド・サーバーの名前を指定します。

    • apply_user - 新しい適用ユーザーを指定します。

例10-4 インバウンド・サーバーの適用ユーザーの変更

xinという名前のインバウンド・サーバーの適用ユーザーをhrに変更するには、次のプロシージャを実行します。

BEGIN
  DBMS_XSTREAM_ADM.ALTER_INBOUND(
    server_name => 'xin',
    apply_user  => 'hr');
END;
/

10.6 XStream Inの競合の検出および解消の管理

複数のクライアントが同じ表の行をほぼ同時に変更すると、競合が発生する可能性があります。XStream Inは競合を検出し、競合を解消するための方法を提供します。

10.6.1 XStream環境内のDMLの競合

競合とは、LCR内の古い値と、表内のデータが一致しないことです。

複数データベース上で同じデータに対して同時のデータ操作言語(DML)操作を許可しているXStream環境では、競合が発生する可能性があります。XStream環境でDMLの競合が発生する可能性があるのは、インバウンド・サーバーがDML操作によって生じる行の変更を含む行LCRを適用している場合のみです。インバウンド・サーバーは、行LCRで発生した競合を自動的に検出します。

たとえば、異なるデータベースで発生した2つのトランザクションによって同じ行がほぼ同時に更新されると、競合が発生する場合があります。XStream環境の構成時には、競合の発生を許可するかどうかを考慮する必要があります。システム設計で競合が許可されている場合は、競合を自動的に解消するように競合解消を構成できます。

一般的なベスト・プラクティスは、起こりうる競合を防止するXStream環境を設計することです。この章で後述する競合防止技法を使用すると、ほとんどのシステム設計で共有データ全体または大部分における競合を防止できます。ただし、多くのアプリケーションでは、複数のデータベースで共有データをある程度の割合まで随時更新可能にする必要があります。この場合は、競合の可能性への対処が必要となります。

注意:

インバウンド・サーバーではDDLの競合が検出されません。この種の競合が環境で防止されることを確認してください。

関連トピック

10.6.2 XStream環境内の競合のタイプ

複数のデータベースでデータを共有する場合は、いくつかの異なるタイプの競合が発生する可能性があります。

10.6.2.1 XStream環境内の更新の競合

更新の競合が発生するのは、インバウンド・サーバーで適用される行LCRに含まれている行の更新が、同じ行の他の更新と競合する場合です。

また、異なるデータベースからの2つのトランザクションによって、同じ行がほぼ同時に更新される場合にも、更新の競合が発生する可能性があります。

10.6.2.2 XStream環境内の一意性競合

一意性競合が発生するのは、インバウンド・サーバーで適用される行LCRに含まれている行の変更が、PRIMARY KEY制約やUNIQUE制約など、一意性の整合性制約に違反している場合です。

たとえば、2つの異なるデータベースからの2つのトランザクションがあり、それぞれのトランザクションが同じ主キー値を持つ表に1行を挿入する場合を考えます。この場合は、これらのトランザクションによって一意性競合が発生します。

10.6.2.3 XStream環境内の削除の競合

削除の競合 が発生するのは、異なるデータベースで発生した2つのトランザクションがあり、1つのトランザクションで1行を削除し、もう1つのトランザクションで同じ行を更新または削除する場合です。

この場合、行LCR内で参照される行は存在しないため、更新または削除できません。

10.6.2.4 XStream環境内の外部キーの競合

外部キーの競合が発生するのは、インバウンド・サーバーで適用される行LCRに含まれている行の変更が、外部キー制約に違反している場合です。

たとえば、hrスキーマ内で、employees表のdepartment_id列は、departments表のdepartment_id列の外部キーです。次の変更が2つの異なるデータベース(AB)で発生し、3つ目のデータベース(C)に伝播される場合を考えます。

  • データベースAで、department_id271の1行がdepartments表に挿入されます。この変更はデータベースBに伝播され、そこで適用されます。

  • データベースBで、employee_id206department_id271の1行がemployees表に挿入されます。

データベースBで発生した変更がデータベースAで発生した変更よりも先にデータベースCで適用されると、データベースCdepartments表にはまだdepartment_id271の部門の行が存在しないため、外部キーの競合が発生します。

10.6.3 XStream環境内の競合とトランザクションの順序付け

XStream環境では、3つ以上のデータベースがデータを共有し、そのうち2つ以上のデータベースでデータが更新されると、順序付けの競合が発生する可能性があります。

たとえば、3つのデータベースがhr.departments表の情報を共有している使用例を考えます。データベースの名前はmult1.example.commult2.example.comおよびmult3.example.comです。mult1.example.comhr.departments表の1行が変更され、その変更がmult2.example.commult3.example.comの両方に伝播されると想定します。次の一連のアクションが発生する可能性があります。

  1. 変更がmult2.example.comに伝播します。

  2. mult2.example.comのインバウンド・サーバーは、mult1.example.comからの変更を適用します。

  3. mult2.example.comで、同じ行に対して別の変更が行われます。

  4. mult2.example.comでの変更がmult3.example.comに伝播します。

  5. mult3.example.comのインバウンド・サーバーは、mult3.example.comの別のインバウンド・サーバーがmult1.example.comからの変更を適用する前に、mult2.example.comからの変更を適用しようとします。

この場合、mult3.example.comでの行の列値はmult2.example.comから伝播した行LCR内の対応する元の値と一致しないため、競合が発生します。

トランザクションが順不同で適用されると、データ競合の原因となるのみでなく、データのサポートがリモート・データベースに正常に伝播されていないと、そのデータベースで参照整合性の問題が発生する場合があります。新規の顧客が受注部門に連絡する場合の使用例を考えます。顧客レコードが作成され、受注が処理されます。リモート・データベースで受注データが顧客データより前に適用されると、受注で参照されている顧客はリモート・データベースに存在しないため、参照整合性エラーが発生します。

順序付けの競合が発生した場合は、必要なデータがリモート・データベースに伝播して適用されてから、エラー・キューにあるトランザクションを再実行すれば、競合を解消できます。

10.6.4 XStream環境内の競合検出

インバウンド・サーバーは自動的に競合を検出します。

10.6.4.1 XStream環境内の競合検出について

インバウンド・サーバーは、更新、一意性、削除および外部キーの競合を検出します。

インバウンド・サーバーは、これらの競合を次のように検出します。

  • 行LCR内の行の元の値と、宛先データベースにある同じ行の現行の値が一致しない場合は、インバウンド・サーバーによって更新の競合が検出されます。

  • 挿入または更新操作を含むLCRの適用時に一意制約違反が発生すると、インバウンド・サーバーによって一意性競合が検出されます。

  • 更新または削除操作を含むLCRの適用時に、行の主キーが存在しないためにその行が見つからないと、インバウンド・サーバーによって削除の競合が検出されます。

  • LCRの適用時に外部キー制約違反が発生すると、インバウンド・サーバーによって外部キーの競合が検出されます。

競合は、インバウンド・サーバーがLCRを直接適用しようとしたとき、またはDML競合ハンドラなどのインバウンド・サーバー・ハンドラがLCRに対してEXECUTEメンバー・プロシージャを実行したときに検出される場合があります。また、DBMS_APPLY_ADMパッケージのEXECUTE_ERRORまたはEXECUTE_ALL_ERRORSプロシージャの実行時にも、競合が検出される場合があります。

注意:

  • 列を更新して、この列の古い値と新しい値が等しい場合、Oracle Databaseではこの列の更新で競合は検出されません。

  • 更新LCR、削除LCRおよびLOB列に対するピース単位更新を取り扱うLCR内の古いLOB値は、競合検出には使用されません。

10.6.4.2 非キー列の競合検出の制御

デフォルトでは、インバウンド・サーバーは競合検出中にすべての列の古い値を比較しますが、DBMS_APPLY_ADMパッケージのCOMPARE_OLD_VALUESプロシージャを使用すると、非キー列の競合検出を停止できます。

競合検出は、一部の非キー列では不要な場合があります。

10.6.4.3 XStream環境内の競合検出中の行の識別

Oracle Databaseは、競合を正確に検出するために、異なるデータベースで対応する行を一意に識別して一致させることができる必要があります。

デフォルトでは、Oracle Databaseは表の主キーを使用してその表の各行を一意に識別します。表に主キーが存在しない場合は、代替キーを指定することがベスト・プラクティスです。代替キーとは、Oracle Databaseが表の各行を一意に識別するために使用できる列または列セットです。

10.6.5 XStream環境内の競合防止

データの競合を防止するためのいくつかの方法があります。

10.6.5.1 プライマリ・データベース所有権モデルの使用

共有データを含む表への同時更新アクセスを行うデータベースの数を制限することによって、競合の可能性を回避できます。

プライマリ所有権を使用すると、共有データ・セットへの更新が1つのデータベースにしか許可されないため、すべての競合が防止されます。アプリケーションでは、行と列のサブセットを使用して、データの所有権を表レベルよりも細かく設定できます。たとえば、アプリケーションでは、共有表の特定の列や行への更新アクセス権を、データベースごとに設定できます。

10.6.5.2 特定タイプの競合の防止

プライマリ・データベース所有権モデルではアプリケーション要件にとって限定的すぎる場合は、共有所有権データ・モデルを使用できますが、これは、競合が発生する可能性があることを意味します。その場合でも、通常は、特定のタイプの競合を回避するためにいくつかの簡単な方法を使用する必要があります。

10.6.5.2.1 XStream環境内の一意性競合の防止

各データベースで共有データに一意識別子を使用させることで、一意性競合を回避できます。

XStream環境ですべてのデータベースに一意識別子を確実に使用させるには、3つの方法があります。

  • その1つは、次のSELECT文を実行して一意識別子を構成することです。

    SELECT SYS_GUID() OID FROM DUAL;
    

    このSQL演算子は、16バイトのグローバル一意識別子を戻します。グローバルに一意な識別子は、次の形式で表示されます。

    A741C791252B3EA0E034080020AE3E0A
    
  • また、データを共有する各データベースで順序を作成し、データベース名(または他のグローバル一意値)をローカルの順序と連結して一意性競合を防止する方法もあります。このアプローチを使用すると、重複する順序値を回避し、一意性競合を防止できます。

  • 最後に、2つのデータベースで同じ値を生成できないように、データを共有する各データベースでカスタマイズされた順序を作成する方法があります。これを実現するには、CREATE SEQUENCE文で開始値、増分値および最大値の組合せを使用します。たとえば、次の順序を構成できます。

    表10-1 カスタマイズされた順序

    パラメータ データベースA データベースB データベースC

    START WITH

    1

    3

    5

    INCREMENT BY

    10

    10

    10

    範囲の例

    1, 11, 21, 31, 41,...

    3, 13, 23, 33, 43,...

    5, 15, 25, 35, 45,...

    同様のアプローチを使用すると、データベースごとに一意の範囲を生成するSTART WITHおよびMAXVALUEを指定して、各データベースに異なる範囲を定義できます。

10.6.5.2.2 Oracle Streams環境内の削除の競合の防止

共有データ環境では、削除の競合を必ず回避してください。

一般的に、共有所有権データ・モデル内で動作するアプリケーションでは、DELETE文を使用した行の削除を防止することがベスト・プラクティスです。かわりに、アプリケーションで行に削除マークを付けておき、論理的に削除された行を定期的にパージするようにシステムを構成できます。

10.6.5.2.3 XStream環境内の更新の競合の防止

一意性競合と削除の競合の可能性を排除した後、更新の競合の発生可能数も制限する必要があります。

ただし、共有所有権データ・モデルでは、更新の競合をすべて回避することはできません。更新の競合を全面的に防止できない場合は、可能な競合のタイプを把握したうえで、それが発生した場合は解消するようにシステムを構成する必要があります。

10.6.6 XStream環境内の競合解消

更新の競合が検出された場合、競合ハンドラではその解消を試みることができます。

10.6.6.1 XStream環境内の競合解消について

XStreamには、挿入および更新の競合を解消するためのビルトインの競合ハンドラが用意されています。

削除、外部キーまたは順序付けの競合には、ビルトインの競合ハンドラはありません。ただし、ビジネス・ルールに固有のデータ競合を解消するために、独自のカスタム競合ハンドラを作成できます。この種の競合ハンドラは、プロシージャDMLハンドラまたはエラー・ハンドラに付属させることができます。

ビルトイン競合ハンドラとカスタム競合ハンドラのどちらを使用する場合も、競合が検出されるとただちに使用されます。指定した競合ハンドラでも関連する適用ハンドラでも競合を解消できない場合、その競合はエラー・キューに記録されます。競合が発生した場合は、関連する適用ハンドラを使用してデータベース管理者に通知する必要があります。

競合のためにトランザクションがエラー・キューに移動される場合は、競合の原因となった条件を訂正できる場合があります。このような場合は、DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを使用してトランザクションを再実行できます。

関連項目:

DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照

10.6.6.2 ビルトインのDML競合ハンドラ

使用できるビルトインのDML競合ハンドラにはいくつかのタイプがあります。列リストおよび解消列はビルトインのDML競合ハンドラで使用されます。

列リストは、挿入または更新の競合がある場合にDML競合ハンドラがコールされる列のリストです。解消列は、DML競合ハンドラを識別します。ビルトインのDML競合ハンドラMAXIMUMまたはMINIMUMを使用する場合は、解消列も競合の解消に使用されます。解消列は、ハンドラの列リスト内の列の1つである必要があります。

特定の表について1つ以上のDML競合ハンドラを指定するには、DBMS_APPLY_ADMパッケージのSET_DML_CONFLICT_HANDLERプロシージャを使用します。削除または外部キーの競合には、ビルトインのDML競合ハンドラはありません。

関連項目:

10.6.6.3 ビルトインのDML競合ハンドラのタイプ

Oracleには、Oracle Streams環境用にRECORDIGNOREOVERWRITEMAXIMUMMINIMUMおよびDELTAタイプのビルトインのDML競合ハンドラが用意されています。

このトピックで後述する各タイプのハンドラの説明では、次の競合例について取り上げます。

  1. dbs1.example.comソース・データベースで次の更新が行われます。

    UPDATE hr.employees SET salary = 4900 WHERE employee_id = 200;
    COMMIT;
    

    この更新によって、従業員200の給与が4400から4900に変更されます。

  2. ほぼ同時に、dbs2.example.com宛先データベースで次の更新が行われます。

    UPDATE hr.employees SET salary = 5000 WHERE employee_id = 200;
    COMMIT;
    
  3. 取得プロセスは、dbs1.example.comソース・データベースで更新を取得し、結果の行LCRをキューに入れます。

  4. 伝播はdbs1.example.comのキューからdbs2.example.comのキューに行LCRを伝播させます。

  5. dbs2.example.comの適用プロセスは、行LCRをhr.employees表に適用しようとしますが、dbs2.example.comの給与値は5000であり、これは行LCR内の給与の元の値(4400)と一致しないため、競合が発生します。

ここでは、各ビルトイン競合ハンドラと、それぞれがこの競合をどのように解消するかについて説明します。

RECORD

競合が発生した場合、RECORDハンドラはLCRをエラー・キューに配置します。RECORDハンドラはすべての競合タイプに使用できますが、表内のすべての列を含む列グループに対してのみ指定できます。

RECORDハンドラを競合例のdbs2.example.com宛先データベースのhr.employees表に使用すると、dbs1.example.comの行LCRはdbs1.example.comのエラー・キューに配置され、その変更は適用されません。したがって、競合解消後は、dbs2.example.comでの従業員200の給与は5000となります。

IGNORE

競合が発生すると、IGNOREハンドラはソース・データベースからのLCR内の値を無視し、宛先データベースの値を保持します。

IGNOREハンドラを競合例のdbs2.example.com宛先データベースのhr.employees表に使用すると、行LCR内の新規の値が廃棄されます。したがって、競合解消後は、dbs2.example.comでの従業員200の給与は5000となります。

OVERWRITE

競合が発生すると、OVERWRITEハンドラは、宛先データベースの現行の値をソース・データベースからのLCR内の新規の値で置換します。

OVERWRITEハンドラを競合例のdbs2.example.com宛先データベースのhr.employees表に使用すると、行LCR内の新規の値によってdbs2.example.comの値が上書きされます。したがって、競合解消後は、従業員200の給与は4900となります。

MAXIMUM

競合が発生すると、MAXIMUM競合ハンドラは、指定された解消列について、ソース・データベースからのLCRにある新規の値を、宛先データベース内の現行の値と比較します。LCRにある解消列の新規の値が宛先データベースの列の現行値より大きければ、適用プロセスではLCRを使用して競合が解消されます。LCRにある解消列の新規の値が宛先データベースの列の現行値より小さければ、適用プロセスでは宛先データベースを使用して競合が解消されます。

MAXIMUMハンドラを競合例のdbs2.example.com宛先データベースにあるhr.employees表のsalary列に使用すると、行LCRにある給与は表にある現行の給与より小さいため、適用プロセスでは行LCRは適用されません。したがって、競合解消後は、dbs2.example.comでの従業員200の給与は5000となります。

関係するトランザクションの時間ベースで競合を解消する場合は、トリガーを使用してトランザクションの時刻が自動的に記録されるように、共有表に列を追加する方法があります。この場合は、この列をMAXIMUM競合ハンドラ用の解消列として指定でき、最新(または最大)時刻を伴うトランザクションが自動的に使用されます。

ここでは、hr.employees表に対するトランザクションの時刻を記録するトリガーの例を示します。job_idsalaryおよびcommission_pct列は、競合解消ハンドラの列リストに含まれているとします。トリガーは、列リスト内の列に対してUPDATEが実行されるか、INSERTが実行された場合にのみ起動します。

ALTER TABLE hr.employees ADD (time TIMESTAMP WITH TIME ZONE);

CREATE OR REPLACE TRIGGER hr.insert_time_employees
BEFORE 
  INSERT OR UPDATE OF job_id, salary, commission_pct ON hr.employees
FOR EACH ROW
BEGIN
   -- Consider time synchronization problems. The previous update to this 
   -- row might have originated from a site with a clock time ahead of the 
   -- local clock time.
   IF :OLD.TIME IS NULL OR :OLD.TIME < SYSTIMESTAMP THEN
     :NEW.TIME := SYSTIMESTAMP;
   ELSE
     :NEW.TIME := :OLD.TIME + 1 / 86400;
   END IF;
END;
/

この種のトリガーを競合解消に使用する場合は、トリガーの起動プロパティがデフォルトの「1回起動」に設定されていることを確認してください。設定が異なると、適用プロセスによってトランザクションが適用されるときに新規時刻がマークされ、トランザクションの実際時刻が失われる可能性があります。

MINIMUM

競合が発生すると、MINIMUM競合ハンドラは、指定された解消列について、ソース・データベースからのLCRにある新規の値を、宛先データベース内の現行の値と比較します。LCRにある解消列の新規の値が宛先データベースの列の現行値より小さければ、適用プロセスではLCRを使用して競合が解消されます。LCRにある解消列の新規の値が宛先データベースの列の現行値より大きければ、適用プロセスでは宛先データベースを使用して競合が解消されます。

MINIMUMハンドラを競合例のdbs2.example.com宛先データベースにあるhr.employees表のsalary列に使用すると、行LCRにある給与は表にある現行の給与より小さいため、適用プロセスでは行LCRを使用して競合が解消されます。したがって、競合解消後は、従業員200の給与は4900となります。

DELTA

競合が発生すると、DELTA競合ハンドラは、列の古い値と新しい値の差を計算し、この差を列の現在の値に加算します。DELTA競合ハンドラは、conflict_typeROW_EXISTSに設定され、列グループ内のすべての列が数値の場合にのみ使用できます。

DELTAハンドラを競合例のdbs2.example.com宛先データベースにあるhr.employees表のsalary列に使用すると、適用プロセスでは、列の古い値と新しい値の差を計算し(4900 – 4400 = 500)、列の現在の値に差を加算する(5000 + 500 = 5500)ことによって競合が解消されます。したがって、競合解消後は、従業員200の給与は5500となります。

MAX_AND_EQUALS

競合が発生したとき、解消列の値がデータベース内の列の値以上である場合にLCRからの列リストを適用します。それ以外の場合は、LCRは破棄されます。

MAX_AND_EQUALSハンドラを競合例のdbs2.example.com宛先データベースのhr.employees表のsalary列に使用すると、適用プロセスではLCRを破棄することによって競合が解消されます。したがって、競合解消後は、従業員200の給与は5000となります。

MIN_AND_EQUALS

競合が発生したとき、解消列の値がデータベース内の列の値以下である場合にLCRからの列リストを適用します。それ以外の場合は、LCRは破棄されます。

MIN_AND_EQUALSハンドラを競合例のdbs2.example.com宛先データベースのhr.employees表のsalary列に使用すると、適用プロセスではLCRを適用することによって競合が解消されます。したがって、競合解消後は、従業員200の給与は4900となります。

10.6.6.4 列リスト

表に対してビルトインのDML競合ハンドラを指定するたびに、列リストを指定する必要があります。

列リストは、DML競合ハンドラがコールされる列のリストです。インバウンド・サーバーが行LCRを適用するときに、リスト内の1つ以上の列に更新の競合が発生すると、競合を解消するためにDML競合ハンドラがコールされます。リストにない列にのみ競合が発生した場合、DML競合ハンドラはコールされません。競合解消の有効範囲は、1つの行LCRの1つの列リストです。

特定の表に対してDML競合ハンドラを複数指定することはできますが、同じ列を複数の列リストに含めることはできません。たとえば、hr.employees表にビルトインのDML競合ハンドラを2つ指定する場合を考えます。

  • 最初のDML競合ハンドラの列リストには、列salaryおよびcommission_pctを指定します。

  • 2番目のDML競合ハンドラの列リストには、列job_idおよびdepartment_idを指定します。

また、この表に他の競合ハンドラは存在しないものと想定します。この場合、次の例は様々なシナリオの結果を示しています。

  • インバウンド・サーバーが行LCRを適用するときにsalary列に競合が発生すると、競合を解消するために最初のDML競合ハンドラがコールされます。

  • department_id列に競合が発生すると、競合を解消するために2番目のDML競合ハンドラがコールされます。

  • どの競合ハンドラの列リストにもない列に競合が発生すると、競合ハンドラはコールされず、エラーになります。たとえば、hr.employees表のmanager_id列に競合が発生すると、エラーになります。

  • 行LCRの適用時に複数の列リストに競合が発生し、列リストに属さない列での競合がなければ、競合が発生した列リストごとに適切なDML競合ハンドラが起動されます。

列リストを使用すると、データ型ごとに異なるハンドラを使用して競合を解消できます。たとえば、通常、数値データにはMAXIMUMまたはMINIMUM競合ハンドラが適しており、文字データにはOVERWRITEまたはDISCARD競合ハンドラが適しています。

列リストにない列に競合が発生すると、表に対する特定の操作用のエラー・ハンドラがそれを解消しようとします。エラー・ハンドラが競合を解消できない場合や、この種のエラー・ハンドラがない場合は、競合の原因となったトランザクションがエラー・キューに移動されます。

また、OVERWRITEMAXIMUMまたはMINIMUMビルトイン・ハンドラのいずれかを使用する列リスト内の列に競合が発生した場合に、この列リスト内のすべての列が行LCRに含まれていないと、使用可能でない値があるため、競合は解消できません。この場合は、競合の原因となったトランザクションがエラー・キューに移動されます。列リストでDISCARDビルトイン方法が使用されている場合は、行LCRにこの列リストのすべての列が含まれていない場合にも、行LCRが廃棄され、エラーは発生しません。

ソース・データベースの複数の列が宛先データベースの列リストに影響を与える場合、列リスト内で指定される列に対して条件付きのサプリメンタル・ログ・グループを指定する必要があります。サプリメンタル・ロギングをソース・データベースで指定し、競合を正しく解消するために必要な情報をLCRに追加します。通常、列リスト内の列に条件付きのサプリメンタル・ログ・グループを指定する必要があるのは、列リストに列が複数存在する場合であり、列リストに存在する列が1つのみの場合は指定する必要ありません。

ただし、列リストに存在する列が1つのみの場合でも、条件付きのサプリメンタル・ログ・グループが必要になることがあります。つまり、適用ハンドラまたはカスタム・ルールベースの変換で、ソース・データベースからの複数列を宛先データベースの列リストの単一行に結合する場合です。たとえば、カスタム・ルールベースの変換で、通り、州および郵便番号を格納するソース・データベースからの3行を使用し、そのデータを宛先データベースで単一の住所列に結合する場合です。

また、列リストに存在する列が複数の場合でも、条件付きのサプリメンタル・ログ・グループが不要なことがあります。たとえば、適用ハンドラまたはカスタム・ルールベースの変換で、ソース・データベースからの単一の住所列を宛先データベースの列リストの複数行に分割する場合です。カスタム・ルールベースの変換で、ソース・データベースの1つの住所列(通り、州および郵便番号を含む)を取得し、そのデータを宛先データベースの3列に分割する場合です。

注意:

ビルトインのDML競合ハンドラでは、LOB、LONGLONG RAW、ユーザー定義型およびOracleが提供する型の列はサポートされません。したがって、SET_DML_CONFLICT_HANDLERプロシージャを実行するときには、column_listパラメータにこれらの型の列を含めないでください。

10.6.6.5 解消列

解消列は、ビルトインのDML競合ハンドラの識別に使用される列です。

ビルトインのDML競合ハンドラMAXIMUMまたはMINIMUMを使用する場合は、解消列も競合の解消に使用されます。解消列は、ハンドラの列リスト内の列の1つである必要があります。

たとえば、hr.employees表のsalary列をMAXIMUMまたはMINIMUM競合ハンドラの解消列として指定すると、行LCR内の列リストの値を適用するか、宛先データベースにおける列リストの値を保持するかを判断するためにsalary列が評価されます。

競合に解消列が関係する次のどちらの状況でも、エラー・ハンドラで問題を解決できない場合は、適用プロセスは競合の原因となった行LCRを含むトランザクションをエラー・キューに移動します。これらの場合、競合は解消できず、宛先データベースの列の値がそのまま保持されます。

  • 解消列について、新規のLCR値と宛先データベースの行の値が同一の場合(解消列が競合の原因となった列でない場合など)。

  • 解消列の新規のLCR値、または宛先データベースの解消列の現行の値がNULLの場合。

注意:

解消列は、OVERWRITEおよびDISCARD競合ハンドラには使用されませんが、解消列をこれらの競合ハンドラ用に指定する必要があります。

10.6.6.6 データ収束

複数のデータベース間でデータを共有しており、そのすべてでデータを同一にする必要がある場合は、すべてのデータベースでデータを収束させる競合解消ハンドラを使用してください。

すべてのデータベースで共有データの変更を許可する場合、表のデータ収束が可能になるのは、データを共有する全データベースが共有データに対する変更を取得し、データを共有する他のすべてのデータベースにその変更を伝播する場合のみです。

このような環境では、MAXIMUM競合解消方法で収束を保証できるのは、解消列の値が常に増加する場合のみです。行の連続するタイム・スタンプがそれぞれ異なっている場合、時間ベースの解消列はこの要件を満たします。このような環境でMINIMUM競合解消方法によって収束を保証できるのは、解消列の値が常に減少する場合のみです。

10.6.6.7 DML競合ハンドラを使用しない衝突処理

表のDML競合ハンドラがない場合、DBMS_APPLY_ADMパッケージのHANDLE_COLLISIONSプロシージャを使用して、基本的な衝突処理を有効にできます。

インバウンド・サーバーと表についての基本的な衝突処理を有効にする場合、競合は次の方法で解消されます。

  • 表に存在する行について競合が検出された場合、行LCRのデータで表内のデータが上書きされます。

    たとえば、行LCRに挿入が含まれているが、行がすでに表に存在するとします。行LCR内のデータで表内の既存のデータが上書きされます。行LCRに更新が含まれており、行の古い値が行LCRの古い値と一致しない場合、行LCRのデータで表内のデータが上書きされます。

  • 表に存在しない行について競合が検出された場合、行LCRのデータは無視されます。

    たとえば、行LCRに行の更新が含まれているが、行が表に存在しない場合、行LCRは無視されます。

例10-5 表の基本的な衝突処理の有効化

この例では、app_empインバウンド・サーバーおよびhr.employees表の基本的な衝突処理が有効になります。
BEGIN
  DBMS_APPLY_ADM.HANDLE_COLLISIONS(
    apply_name => 'app_emp',
    enable     => TRUE,
    object     => 'hr.employees');
END;
/

この表の基本的な衝突処理を無効にするには、同じプロシージャを実行しますが、enableパラメータをFALSEに設定します。

10.6.6.8 カスタム競合ハンドラ

PL/SQLプロシージャを作成し、カスタム競合ハンドラとして使用できます。

特定の表に1つ以上のカスタム競合ハンドラを指定するには、DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを使用します。特に、このプロシージャを実行してカスタム競合ハンドラを指定するときに、次のパラメータを設定します。

  • object_nameパラメータを、競合解消の対象となる表の完全修飾された名前に設定します。

  • object_typeパラメータをTABLEに設定します。

  • operation_nameパラメータを、カスタム競合ハンドラのコール対象となる操作のタイプに設定します。可能な操作は、INSERTUPDATEDELETEおよびLOB_UPDATEです。また、ハンドラをすべての操作のデフォルト・ハンドラとするために、operation_nameパラメータをDEFAULTに設定できます。

  • エラー・ハンドラでエラー発生時に競合解消を実行する場合は、error_handlerパラメータをTRUEに設定します。また、競合解消をプロシージャDMLハンドラに組み込む場合は、error_handlerパラメータをFALSEに設定します。

    このパラメータをFALSEに設定した場合は、LCR用のEXECUTEメンバー・プロシージャを使用して行LCRを実行すると、指定したオブジェクトと操作に対してプロシージャDMLハンドラ内で競合解消が実行されます。

  • user_procedureパラメータを設定して、競合解消用のプロシージャを指定します。このユーザー・プロシージャは、指定したタイプの操作によって指定した表に生じた競合を解消するためにコールされます。

カスタム競合ハンドラが競合を解消できない場合、インバウンド・サーバーは、競合を含むトランザクションをエラー・キューに移動し、そのトランザクションを適用しません。

特定のオブジェクトにビルトインのDML競合ハンドラとカスタム競合ハンドラの両方が存在する場合は、次の両方の条件が満たされる場合にのみビルトインのDML競合ハンドラが起動されます。

  • カスタム競合ハンドラで、LCR用のEXECUTEメンバー・プロシージャを使用して行LCRが実行される場合。

  • 行LCR用のEXECUTEメンバー・プロシージャのconflict_resolutionパラメータがTRUEに設定されている場合。

関連項目:

SET_DML_HANDLERプロシージャの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照

10.6.7 DML競合ハンドラの管理

DML競合ハンドラを設定および削除できます。既存のDML競合ハンドラを変更するには、DML競合ハンドラ削除して再設定する必要があります。

10.6.7.1 DML競合ハンドラの設定

DBMS_APPLY_ADMパッケージのSET_DML_CONFLICT_HANDLERプロシージャを使用して、DML競合ハンドラを設定します。

DMLの競合解消ハンドラを作成する場合は、次のいずれかのビルトイン方法を使用できます。
  • RECORD

  • IGNORE

  • OVERWRITE

  • MAXIMUM

  • MINIMUM

  • DELTA

  • MAX_AND_EQUALS

  • MIN_AND_EQUALS

DML競合ハンドラを設定するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。
  2. DBMS_APPLY_ADMパッケージのSET_DML_CONFLICT_HANDLERプロシージャを実行します。

例10-6 DML競合ハンドラの設定

仮にXStreamクライアントが、dbs1.example.comhr.jobs表に適用される変更を受信したとします。この環境では、クライアントが受信する外部データベースからの変更が、ターゲット・データベースdbs1.example.comへの変更と調整されていない可能性があるため、競合が発生する場合があります。特定のDMLの挿入または更新について競合が発生している場合、外部データベースからの変更が、常にターゲット・データベースでの変更を上書きする必要があります。この環境では、dbs1.example.comデータベースでOVERWRITEハンドラを指定して、この目標を達成できます。DMLの削除用の行が存在しないため競合が発生している場合、その行LCRは無視されます。

この例では、dbs1.example.comデータベースのhr.jobs表のためのDML競合ハンドラを指定します。

DECLARE
  cols DBMS_UTILITY.LNAME_ARRAY;
  BEGIN
    cols(1) := 'job_title';
    cols(2) := 'min_salary';
    cols(3) := 'max_salary';
    DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
      apply_name            => 'app_jobs',
      conflict_handler_name => 'jobs_handler_insert',
      object                => 'hr.jobs',
      operation_name        => 'INSERT',
      conflict_type         => 'ROW_EXISTS',
      method_name           => 'OVERWRITE',
      column_table          => cols);
    DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
      apply_name            => 'app_jobs',
      conflict_handler_name => 'jobs_handler_update',
      object                => 'hr.jobs',
      operation_name        => 'UPDATE',
      conflict_type         => 'ROW_EXISTS',
      method_name           => 'OVERWRITE',
      column_table          => cols);
    DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
      apply_name            => 'app_jobs',
      conflict_handler_name => 'jobs_handler_delete',
      object                => 'hr.jobs',
      operation_name        => 'DELETE',
      conflict_type         => 'ROW_MISSING',
      method_name           => 'IGNORE',
      column_list           => '*');
END;
/

適用プロセスapp_jobsは指定されたDML競合ハンドラを使用します。

注意:

  • jobs_handler_delete DML競合ハンドラについては、operation_nameDELETEに設定されたときに、すべての列が指定される必要があるため、column_listパラメータは'*'に設定されます。

  • クライアントがXStream Outを使用してOracleデータベースからデータを取得する場合は、宛先データベースのcolumn_listにあるすべての列について、ソース・データベースで条件付きのサプリメンタル・ログ・グループを指定する必要があります。この例では、外部データベースのhr.jobs表のjob_titlemin_salaryおよびmax_salary列を含む条件付きのサプリメンタル・ログ・グループを指定します。

  • ビルトインのDML競合ハンドラでは、LOB、LONGLONG RAW、ユーザー定義型およびOracleが提供する型の列はサポートされません。したがって、SET_DML_CONFLICT_HANDLERプロシージャを実行するときには、column_listパラメータにこれらの型の列を含めないでください。

関連項目:

データ型の詳細は、Oracle Database SQL言語リファレンスを参照
10.6.7.2 DML競合ハンドラの削除

DBMS_APPLY_ADMパッケージのSET_DML_CONFLICT_HANDLERプロシージャを実行すると、既存のDML競合ハンドラを削除できます。

既存のDML競合ハンドラを削除するには、メソッドにNULLを指定し、既存のDML競合ハンドラと同じ適用名およびDML競合ハンドラ名を指定します。

DML競合ハンドラを削除するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。
  2. メソッドにNULLを指定してDBMS_APPLY_ADMパッケージのSET_DML_CONFLICT_HANDLERプロシージャを実行し、既存のDML競合ハンドラと同じ適用名、DML競合ハンドラ名、オブジェクト名、競合タイプおよび解消列を指定します。

例10-7 DML競合ハンドラの削除

DML競合ハンドラの設定で作成されたDML競合ハンドラを削除するには、次の手順を実行します。

BEGIN
  DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
     apply_name            => 'app_jobs',
     conflict_handler_name => 'jobs_handler_insert',
     method_name           => NULL);
  DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
     apply_name            => 'app_jobs',
     conflict_handler_name => 'jobs_handler_update',
     method_name           => NULL);
  DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
     apply_name            => 'app_jobs',
     conflict_handler_name => 'jobs_handler_delete',
     method_name           => NULL);
END;
/

10.6.8 非キー列の競合検出の停止

DBMS_APPLY_ADMパッケージのCOMPARE_OLD_VALUESプロシージャを使用すると、非キー列の競合検出を停止できます。

非キー列の競合検出を停止するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。
  2. DBMS_APPLY_ADMパッケージのCOMPARE_OLD_VALUESプロシージャを実行して、非キー列を指定し、compareパラメータにFALSEを指定します。

例10-8 非キー列の競合検出の停止

仮に、hr.employees表の競合解消用にtime列を構成したとします。表に変更があるたびに、トリガーによってこの列に現在の時刻が記録されます。この場合、表の他の非キー列の競合検出を停止するように指定できます。hr.employees表の列を更新競合ハンドラの列リストに追加します。

DECLARE
  cols  DBMS_UTILITY.NAME_ARRAY;
BEGIN
  cols(1)  := 'first_name';
  cols(2)  := 'last_name';
  cols(3)  := 'email';
  cols(4)  := 'phone_number';
  cols(5)  := 'hire_date';
  cols(6)  := 'job_id';
  cols(7)  := 'salary';
  cols(8)  := 'commission_pct';
  cols(9)  := 'manager_id';
  cols(10) := 'department_id';
  cols(11) := 'time';
  DBMS_APPLY_ADM.SET_DML_CONFLICT_HANDLER(
    apply_name            => 'app_employees',
    conflict_handler_name => 'emp_handler',
    object                => 'hr.employees',
    operation_name        => 'UPDATE',
    conflict_type         => 'ROW_EXISTS',
    method_name           => 'MAXIMUM',
    column_list           => cols,
    resolution_column     => 'time');
END;
/

この例では、主キーに更新がないことを想定しているため、列リストに表の主キーは含まれていません。ただし、他のキー列は列リストに含まれています。

UPDATE操作に対する表内のすべての非キー列の競合検出を停止するには、次のように入力します。

DECLARE
  cols DBMS_UTILITY.LNAME_ARRAY;
  BEGIN
    cols(1) := 'first_name';
    cols(2) := 'last_name';
    cols(3) := 'email';
    cols(4) := 'phone_number';
    cols(5) := 'hire_date';
    cols(6) := 'job_id';
    cols(7) := 'salary';
    cols(8) := 'commission_pct';  
  DBMS_APPLY_ADM.COMPARE_OLD_VALUES(
    object_name  => 'hr.employees',
    column_table => cols, 
    operation    => '*',
    compare      => FALSE);
END;
/

operationパラメータに指定されるアスタリスク(*)は、UPDATE操作について競合検出が停止されたことを意味します。このプロシージャを実行すると、データベース上で実行中の、指定の表に変更をローカルに適用するすべての適用プロセスでは、指定した列の競合は検出されません。したがって、この例では、time列のみが競合検出に使用されます。

注意:

この項の例では、DML競合ハンドラを設定してから、非キー列の競合検出を停止しています。ただし、非キー列の競合検出を停止する前に、DML競合ハンドラは必要ありません。

関連項目:

COMPARE_OLD_VALUESプロシージャの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照

10.7 適用エラーの管理

インバウンド・サーバーがLCRを適用する際に適用エラーが起きると、エラーが発生します。

適用エラーが発生すると、エラーが発生したLCRおよび同じトランザクション内の他のすべてのLCRがエラー・キューに移動されます。

関連項目:

10.7.1 インバウンド・サーバーのエラー処理

特定のタイプのエラーを処理するためのエラー・ハンドラを構成できます。

10.7.1.1 エラー・ハンドラについて

エラー・ハンドラは、適用中の特定のエラーを処理するためのメソッドを指定します。

インバウンド・サーバーで行LCRが適用される際、エラーが発生することがあります。DBMS_APPLYパッケージのSET_REPERROR_HANDLERプロシージャで指定されたメソッドを使用して、特定のエラーを処理するためのエラー・ハンドラを構成できます。たとえば、行LCRが表に存在しない行を更新または削除しようとしたときに発生するORA-26787エラーを処理するエラー・ハンドラを設定できます。また、特定のエラーを指定せずにデフォルトのエラー処理方法を構成できます。

エラー・ハンドラは、特定の適用プロセスに対して設定します。特定の表またはすべての表に対してエラー・ハンドラを設定できます。

次の表では、各エラー・ハンドラ・メソッドについて説明します。

表10-2 エラー・ハンドラ・メソッド

メソッド 説明
ABEND

エラーが発生した場合、インバウンド・サーバーを停止します。

RECORD

エラーが発生した場合、エラーの原因となった行LCRをエラー・キューに移動します。

IGNORE

エラーが発生した場合、警告を出さずにエラーを無視し、LCR行を適用しません。

RETRY

エラーが発生した場合、指定された回数だけ行LCRを再試行します。

再試行が失敗した場合、トランザクション全体がエラー・キューに移されます。

RETRY_TRANSACTION

エラーが発生した場合、指定された遅延の後に、指定された回数だけトランザクションを再試行します。

再試行が失敗した場合、トランザクション全体がエラー・キューに移されます。

RECORD_TRANSACTION

エラーが発生した場合、トランザクション全体をエラー・キューに移動します。RECORD_TRANSACTIONがデフォルトになります。

10.7.1.2 エラー・ハンドラの設定および設定解除

DBMS_APPLYパッケージのSET_REPERROR_HANDLERプロシージャを使用してエラー・ハンドラを設定します。

エラー・ハンドラを設定する場合は、次のいずれかの方法を使用できます。
  • ABEND

  • RECORD

  • IGNORE

  • RETRY

  • RETRY_TRANSACTION

  • RECORD_TRANSACTION

エラー・ハンドラの設定を解除するには、SET_REPERROR_HANDLERプロシージャのmethodパラメータをNULLに設定します。

エラー・ハンドラを設定または設定解除するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。
  2. DBMS_APPLY_ADMパッケージのSET_REPERROR_HANDLERプロシージャを実行します。

例10-9 特定の表のすべてのエラーについてインバウンド・サーバーを停止するエラー・ハンドラの設定

この例では、oe.orders表のすべてのエラーについてapp_oeインバウンド・サーバーを停止するエラー・ハンドラが設定されます。error_numberパラメータを0に設定すると、すべてのエラーが指定されます。methodパラメータをABENDに設定すると、エラーの発生時にインバウンド・サーバーが停止することが指定されます。

BEGIN
  DBMS_APPLY_ADM.SET_REPERROR_HANDLER(
    apply_name   => 'app_oe',
    object       => 'oe.orders',
    error_number => 0,
    method       => 'ABEND');
END;
/

例10-10 特定の表および特定のエラーについて行LCRを無視するエラー・ハンドラの設定

この例では、app_oeインバウンド・サーバーについてORA-1403エラーが発生する行LCRを無視するエラー・ハンドラを設定します。エラー・ハンドラは、oe.orders表に適用されます。

BEGIN
  DBMS_APPLY_ADM.SET_REPERROR_HANDLER(
    apply_name   => 'app_oe',
    object       => 'oe.orders',
    error_number => 1403,
    method       => 'IGNORE');
END;
/

例10-11 エラー・ハンドラの設定解除

この例では、app_oeインバウンド・サーバーについてORA-1403エラーが発生する行LCRを無視するエラー・ハンドラの設定を解除します。エラー・ハンドラは、oe.orders表に対して設定されていました。

BEGIN
  DBMS_APPLY_ADM.SET_REPERROR_HANDLER(
    apply_name   => 'app_oe',
    object       => 'oe.orders',
    error_number => 1403,
    method       => NULL);
END;
/

10.7.2 適用エラー・トランザクションの再試行

特定のエラー・トランザクションだけ、または1つのインバウンド・サーバーのすべてのエラー・トランザクションを再試行できます。

エラー・トランザクションを再試行する前に、データベース・オブジェクトに対してDML変更またはDDL変更を行い、1つ以上の適用エラーの原因となった状態を修正することが必要な場合もあります。

関連項目:

現行セッションで生成されるタグの値の設定の詳細は、Oracle Streamsレプリケーション管理者ガイドを参照

10.7.2.1 特定の適用エラー・トランザクションの再試行

エラー・トランザクションを再試行する場合は、直接実行することも、ユーザー・プロシージャにエラー・トランザクションを送信して変更した後で実行することもできます。

関連項目:

EXECUTE_ERRORプロシージャの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照

10.7.2.1.1 ユーザー・プロシージャを使用しない特定の適用エラー・トランザクションの再試行

適用エラーの原因となった条件を修正した後に、ユーザー・プロシージャを指定せずにDBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを実行して、トランザクションを再試行できます。この場合、トランザクションはカスタム処理を使用せずに実行されます。

複数のエラー・トランザクションがある場合、エラー・トランザクションを実行するときにトランザクションの順序が重要になることがあります。一般的に、最も古いトランザクションを最初に実行し、最新のトランザクションに到達するまでそれぞれの後続のトランザクションを順番に実行するのがベスト・プラクティスです。DBA_APPLY_ERRORビューのSOURCE_COMMIT_POSITION列にはトランザクション時間が表示されます。

ユーザー・プロシージャを使用しない特定の適用エラー・トランザクションの再試行を行うには、次のようにします。

  1. SQL*Plusで、データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを実行して、トランザクション識別子を指定します。

    トランザクション識別子が5.4.312のトランザクションを再試行するには、次のプロシージャを実行します。

    BEGIN
      DBMS_APPLY_ADM.EXECUTE_ERROR(
        local_transaction_id => '5.4.312',
        execute_as_user      => FALSE,
        user_procedure       => NULL);
    END;
    /
    

execute_as_userTRUEの場合は、インバウンド・サーバーでは、現行ユーザーのセキュリティ・コンテキスト内でトランザクションが実行されます。execute_as_userFALSEの場合、インバウンド・サーバーでは、トランザクションの元の受信者のセキュリティ・コンテキスト内でトランザクションが実行されます。元の受信者とは、エラー発生時にトランザクションを処理していたユーザーです。

いずれの場合も、トランザクションを実行するユーザーには、適用オブジェクトに対するDML変更およびDDL変更を実行するための権限と、任意の適用ハンドラを実行するための権限が必要です。

10.7.2.1.2 ユーザー・プロシージャを使用した特定の適用エラー・トランザクションの再試行

DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを実行してエラー・トランザクションを再試行できます。また、ユーザー・プロシージャを指定して、トランザクションの実行前に、トランザクション内の1つ以上のLCRを変更することもできます。

この変更によって、トランザクションが正常に実行できるはずです。

たとえば、競合が原因で適用エラーが発生した場合を考えてみます。エラー・トランザクションを検証すると、行LCRのsalary列の古い値が間違っていることが判明しました。具体的には、hr.employees表のemployee_id197の従業員について、給料の現行の値が、行LCRにおけるこの従業員の給料の古い値と一致していません。hr.employees表で、この従業員の現行の値が3250であるとします。この項の例では、エラーを解消するプロシージャを作成します。

ユーザー・プロシージャを使用した特定の適用エラー・トランザクションの再試行を行うには、次のようにします。

  1. SQL*Plusで、データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. 前述したこのシナリオで、エラーの原因となった行LCR内のsalaryを変更する次のユーザー・プロシージャを作成します。

    CREATE OR REPLACE PROCEDURE xstrmadmin.modify_emp_salary(
      in_any                        IN      ANYDATA,
      error_record                  IN      ALL_APPLY_ERROR%ROWTYPE,
      error_message_number          IN      NUMBER,
      messaging_default_processing  IN OUT  BOOLEAN,
      out_any                       OUT     ANYDATA)
    AS
      row_lcr          SYS.LCR$_ROW_RECORD;
      row_lcr_changed  BOOLEAN := FALSE;
      res              NUMBER;
      ob_owner         VARCHAR2(32);
      ob_name          VARCHAR2(32);
      cmd_type         VARCHAR2(30);
      employee_id      NUMBER;
    BEGIN
      IF in_any.getTypeName() = 'SYS.LCR$_ROW_RECORD' THEN
        -- Access the LCR
        res := in_any.GETOBJECT(row_lcr);
        -- Determine the owner of the database object for the LCR
        ob_owner := row_lcr.GET_OBJECT_OWNER;
        -- Determine the name of the database object for the LCR
        ob_name := row_lcr.GET_OBJECT_NAME;
        -- Determine the type of DML change
        cmd_type := row_lcr.GET_COMMAND_TYPE;
        IF (ob_owner = 'HR' AND ob_name = 'EMPLOYEES' AND cmd_type = 'UPDATE') THEN
          -- Determine the employee_id of the row change
          IF row_lcr.GET_VALUE('old', 'employee_id') IS NOT NULL THEN
            employee_id := row_lcr.GET_VALUE('old', 'employee_id').ACCESSNUMBER();
            IF (employee_id = 197) THEN
              -- error_record.message_number should equal error_message_number
              row_lcr.SET_VALUE(
              value_type => 'OLD',
              column_name => 'salary',
              column_value => ANYDATA.ConvertNumber(3250));
              row_lcr_changed := TRUE;
            END IF;
          END IF;
        END IF;
      END IF;
      -- Specify that the inbound server continues to process the current message
      messaging_default_processing := TRUE;
      -- assign out_any appropriately
      IF row_lcr_changed THEN
        out_any := ANYDATA.ConvertObject(row_lcr);
      ELSE
        out_any := in_any;
      END IF;
    END;
    /
    
  3. DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを実行して、トランザクション識別子およびユーザー・プロシージャを指定します。

    トランザクション識別子が5.6.924のトランザクションを再試行する際、実行前にxstrmadminスキーマ内のmodify_emp_salaryプロシージャでトランザクションを処理するには、次のプロシージャを実行します。

    BEGIN
      DBMS_APPLY_ADM.EXECUTE_ERROR(
        local_transaction_id => '5.6.924',
        execute_as_user      => FALSE,
        user_procedure       => 'xstrmadmin.modify_emp_salary');
    END;
    /
    

注意:

プロシージャを実行するユーザーには、ALL_APPLY_ERRORデータ・ディクショナリ・ビューに対するSELECT権限が必要です。

10.7.2.2 インバウンド・サーバーについてのすべてのエラー・トランザクションの再試行

インバウンド・サーバーについて、すべての適用エラーの原因となった条件を修正した後に、DBMS_APPLY_ADMパッケージのEXECUTE_ALL_ERRORSプロシージャを実行してすべてのエラー・トランザクションを再試行できます。

インバウンド・サーバーについてのすべてのエラー・トランザクションを再試行するには、次のようにします。

複数のエラー・トランザクションがある場合、EXECUTE_ALL_ERRORSプロシージャは最も古いトランザクションを最初に実行し、最新のトランザクションに到達するまでそれぞれの後続のトランザクションを順番に実行します。

  1. SQL*Plusで、データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_APPLY_ADMパッケージのEXECUTE_ALL_ERRORSプロシージャを実行して、インバウンド・サーバーの名前を指定します。

    xinという名前のインバウンド・サーバーについてのエラー・トランザクションを再試行するには、次のプロシージャを実行します。

    BEGIN
      DBMS_APPLY_ADM.EXECUTE_ALL_ERRORS(
        apply_name       => 'xin',
        execute_as_user  => FALSE);
    END;
    /
    

注意:

apply_nameパラメータに対してNULLを指定した場合に、複数のインバウンド・サーバーが存在すると、すべてのインバウンド・サーバーのすべての適用エラーが再試行されます。

10.7.3 適用エラー・トランザクションの削除

インバウンド・サーバーの特定のエラー・トランザクションまたはすべてのエラー・トランザクションを削除できます。

10.7.3.1 特定の適用エラー・トランザクションの削除

エラー・トランザクションを適用する必要がない場合は、DBMS_APPLY_ADMパッケージのDELETE_ERRORプロシージャを使用して、エラー・キューからトランザクションを削除できます。

特定の適用エラー・トランザクションを削除するには、次のようにします。

  1. SQL*Plusで、データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. 削除するエラー・トランザクションのトランザクションIDを指定します。

    たとえば、次の問合せを実行して、ローカル適用エラー・トランザクションのリストを表示します。

    COLUMN APPLY_NAME FORMAT A11
    COLUMN SOURCE_DATABASE' FORMAT A10
    COLUMN LOCAL_TRANSACTION_ID FORMAT A11
    COLUMN ERROR_NUMBER FORMAT 99999999
    COLUMN ERROR_MESSAGE FORMAT A20
    COLUMN MESSAGE_COUNT FORMAT 99999999
    
    SELECT APPLY_NAME, 
           SOURCE_DATABASE, 
           LOCAL_TRANSACTION_ID, 
           ERROR_NUMBER,
           ERROR_MESSAGE,
           MESSAGE_COUNT
      FROM DBA_APPLY_ERROR;
  3. DBMS_APPLY_ADMパッケージのDELETE_ERRORプロシージャを実行して、トランザクション識別子を指定します。

    トランザクション識別子が5.4.312であるトランザクションを削除するには、次のプロシージャを実行します。

    EXEC DBMS_APPLY_ADM.DELETE_ERROR(local_transaction_id => '5.4.312');
10.7.3.2 インバウンド・サーバーについてのすべてのエラー・トランザクションの削除

すべてのエラー・トランザクションを適用しない場合は、DBMS_APPLY_ADMパッケージのDELETE_ALL_ERRORSプロシージャを実行して、すべてのエラー・トランザクションを削除できます。

インバウンド・サーバーについてのすべてのエラー・トランザクションを削除するには、次のようにします。

  1. SQL*Plusで、データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DBMS_APPLY_ADMパッケージのDELETE_ALL_ERRORSプロシージャを実行して、インバウンド・サーバーの名前を指定します。

    xinという名前のインバウンド・サーバーについてのエラー・トランザクションをすべて削除するには、次の手順を実行します。

    EXEC DBMS_APPLY_ADM.DELETE_ALL_ERRORS(apply_name => 'xin');
    

注意:

apply_nameパラメータに対してNULLを指定した場合に、複数のインバウンド・サーバーが存在すると、すべてのインバウンド・サーバーのすべての適用エラーが削除されます。

10.7.4 インバウンド・サーバーで発生した即時エラーの管理

パフォーマンスを最適化するため、インバウンド・サーバーはコミットLCRを受信する前に、即時適用を使用して大規模なトランザクションの適用を開始できます。

即時適用の詳細は、大規模トランザクションにおけるXStream Inのパフォーマンスの最適化を参照してください。

インバウンド・サーバーがトランザクションを即時に適用するとき、エラーが発生する場合があります。すべてのLCRをトランザクションのために使用できないため、この失敗したトランザクションに対してEAGER ERRORが記録されます。この場合、ALL_APPLY_ERRORビューのエントリにトランザクションの即時エラーが表示されますが、LCRはエラー・キューに記録されません。エラー・トランザクションが即時エラー・トランザクションでない場合は、これは通常エラー・トランザクションと呼ばれます。

通常エラー・トランザクションと即時エラー・トランザクションは、異なる方法で管理する必要があります。インバウンド・サーバーは通常エラー・トランザクションを、そのすべてのLCRを含めてエラー・キューに移しますが、インバウンド・サーバーは即時エラー・トランザクションをエラー・キューに移しません。

即時エラーにより、インバウンド・サーバーは停止します。インバウンド・サーバーが再起動するとき、再起動するトランザクションについてのEAGER ERRORがエラー・キューに存在する場合、トランザクションは通常トランザクションとして開始されます。つまり、大規模トランザクションのLCRはディスクに書き出され、インバウンド・サーバーは、コミットLCRを受信して初めてLCRの適用を開始します。

次の文は、通常エラー・トランザクションと即時エラー・トランザクションの両方に適用されます。

  • ALL_APPLY_ERRORビューおよびALL_APPLY_ERROR_MESSAGESビューには、エラー・トランザクションに関する情報(メタデータ)が含まれています。

  • インバウンド・サーバーはエラー・トランザクションを適用しません。

表10-3は、通常エラー・トランザクションを管理するためのオプションについて説明しています。

表10-3 通常エラー・トランザクションを管理するために使用できるオプション

アクション メカニズム 説明

エラー・トランザクションの削除

DBMS_APPLY_ADM.DELETE_ERROR

DBMS_APPLY_ADM.DELETE_ALL_ERRORS

Oracle Enterprise Manager Cloud Control。

エラー・トランザクションがエラー・キューから削除され、エラー・トランザクションに関するメタデータが削除されます。インバウンド・サーバーが再起動されたとき、インバウンド・サーバーはトランザクションの再実行を試行しません。トランザクションは適用されません。

エラー・トランザクションの実行

DBMS_APPLY_ADM.EXECUTE_ERROR

DBMS_APPLY_ADM.EXECUTE_ALL_ERRORS

Oracle Enterprise Manager Cloud Control。

エラー・キュー内のエラー・トランザクションが実行されます。実行中にエラーが発生しない場合は、そのトランザクションが適用されます。実行中にLCRでエラーが発生した場合、通常エラー・トランザクションは元のエラー・キューに移動されます。

エラー・トランザクションの保持

なし。(エラー・トランザクションは自動的に保持されます。)

エラー・トランザクションは、インバウンド・サーバーが再起動された場合でもエラー・キューに保持されます。エラー・トランザクションに関するメタデータも保持されます。トランザクションは適用されません。

表10-4は、即時エラー・トランザクションを管理するためのオプションについて説明しています。

表10-4 即時エラー・トランザクションを管理するために使用できるオプション

アクション メカニズム 説明

エラー・トランザクションの削除

DBMS_APPLY_ADM.DELETE_ERROR

DBMS_APPLY_ADM.DELETE_ALL_ERRORS

Oracle Enterprise Manager Cloud Control。

即時エラー・トランザクションに関するメタデータが削除されます。インバウンド・サーバーが再起動されると、インバウンド・サーバーはトランザクションを即時トランザクションとして実行しようとします。インバウンド・サーバーの実行中にエラーが発生しない場合、トランザクションは正常に適用されます。インバウンド・サーバーの実行中にエラーが発生した場合、即時エラー・トランザクションが記録されます。

エラー・トランザクションの保持

なし。(エラー・トランザクションに関するメタデータは自動的に保持されます。)

即時エラー・トランザクションに関するメタデータは保持されます。インバウンド・サーバーが再起動されると、インバウンド・サーバーはトランザクションを通常トランザクションとして実行しようとします。

具体的には、インバウンド・サーバーはトランザクションをディスクに書き出し、トランザクションの実行を試行します。インバウンド・サーバーの実行中にエラーが発生しない場合、トランザクションは正常に適用されます。インバウンド・サーバーの実行中にエラーが発生した場合、トランザクションは通常エラー・トランザクションになります。この場合、エラーが発生したLCRおよびそのトランザクション内の他のすべてのLCRがエラー・キューに移されます。通常エラー・トランザクションがエラー・キューに移された後は、エラー・トランザクションを(即時エラー・トランザクションではなく)通常エラー・トランザクションとして管理する必要があります。

注意:

DBMS_APPLY_ADMパッケージまたはOracle Enterprise Manager Cloud Controlを使用して即時エラー・トランザクションを手動で実行しようとすると、次のエラーが表示されます。

ORA-26909: cannot reexecute an eager error

即時エラー・トランザクションは手動で実行できません。かわりに、インバウンド・サーバーが有効化されたときに自動的に実行されます。

インバウンド・サーバーで発生した即時エラー・トランザクションを管理するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. ALL_APPLY_ERRORデータ・ディクショナリ・ビューのERROR_TYPE列を問い合せます。

    SELECT APPLY_NAME, ERROR_TYPE FROM ALL_APPLY_ERROR;
    

    エラー・タイプに基づいて適切な手順を実行します。

  3. LCRで発生したエラー・メッセージを確認し、エラーの原因を特定します。

    関連項目:

    • データ・ディクショナリ・ビューを使用した適用エラー確認の詳細は、適用エラーの確認および適用エラーの詳細情報の表示を参照

    • Oracle Enterprise Manager Cloud Controlを使用した適用エラーの確認については、Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照

  4. 可能であれば、エラーを防止する方法を決定し、エラーを防止するために必要な変更を加えます。

    関連項目:

    一般的な適用エラーおよびその解決策の詳細は、XStream Inのトラブルシューティングを参照

  5. エラー・トランザクションを保持するか、またはエラー・トランザクションを削除します。

    • 問題を修正した場合のみエラー・トランザクションを削除します。インバウンド・サーバーが有効化されるとトランザクションが再実行されます。

      たとえば、トランザクション識別子が5.4.312のトランザクションを削除するには、次のプロシージャを実行します。

      EXEC DBMS_APPLY_ADM.DELETE_ERROR(local_transaction_id => '5.4.312');
      
    • 問題を今すぐ修正できない場合、または後で再実行する予定がある場合は、エラー・トランザクションを保持します。エラー・トランザクションを保持するためのアクションは必要ありません。再実行されるか削除されるまでエラー・キューに残ります。

    これらのオプションの詳細は、表10-4を参照してください。

    注意:

    削除された通常エラー・トランザクションをリカバリできない可能性があります。エラー・トランザクションを削除する前に、そのエラー・タイプがEAGER ERRORであることを確認してください。

    関連項目:

    • DBMS_APPLY_ADMパッケージを使用したエラー・トランザクションの削除の詳細は、適用エラー・トランザクションの削除を参照

    • Oracle Enterprise Manager Cloud Controlを使用したエラー・トランザクションの削除については、Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照してください。

  6. インバウンド・サーバーが無効な場合、インバウンド・サーバーを起動します。

    ALL_APPLY_ERRORビューのSTATUS列を問い合せて、インバウンド・サーバーが有効か無効かを判別します。

    インバウンド・サーバーについてのdisable_on_error適用パラメータがYに設定されている場合、インバウンド・サーバーにエラーが発生するとインバウンド・サーバーは無効化され、無効の状態のままになります。

    インバウンド・サーバーについてのdisable_on_error適用パラメータがNに設定されている場合は、インバウンド・サーバーにエラーが発生するとインバウンド・サーバーは自動的に停止して再起動します。

    インバウンド・サーバーが手順5での選択に基づいてエラー・トランザクションを処理する方法については、表10-4を参照してください。

    関連項目:

    • DBMS_APPLY_ADMパッケージを使用したインバウンド・サーバーまたは適用プロセスの起動に関する情報は、インバウンド・サーバーの起動を参照

    • Oracle Enterprise Manager Cloud Controlを使用したインバウンド・サーバーまたは適用プロセスの起動については、Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照

注意:

Oracle GoldenGate製品のライセンスを購入し、かつDBMS_XSTREAM_ADM.ENABLE_GG_XSTREAM_FOR_STREAMSプロシージャを実行してOracle StreamsのXStream最適化が有効になっている場合、Oracle Streams構成の適用プロセスでEAGER ERRORタイプのエラーが発生する可能性があります。この項の手順を使用して、即時適用プロセス・エラーを管理してください。Oracle StreamsのXStream最適化が有効になっていない場合、適用プロセスに即時エラーが発生することはありません。

10.8 競合およびエラー処理の優先順位

競合またはエラーを解決するために、インバウンド・サーバーは競合ハンドラおよびエラー・ハンドラを見つけようとします。

競合またはエラーが発生すると、インバウンド・サーバーは、エラーに適用される次のタイプのハンドラを指定された順序でチェックすることで問題を解決しようとします。

  1. SET_UPDATE_CONFLICT_HANDLERプロシージャを使用して設定される更新の競合ハンドラ

  2. SET_DML_CONFLICT_HANDLERプロシージャを使用して設定されるカスタム競合ハンドラ

  3. HANDLE_COLLISIONSプロシージャを使用して設定される衝突ハンドラ

  4. SET_REPERROR_HANDLERプロシージャを使用して設定されるエラー・ハンドラ

  5. SET_DML_HANDLERプロシージャを使用して設定されるカスタム競合ハンドラ

これらのプロシージャはすべてDBMS_APPLY_ADMパッケージにあります。

ハンドラが競合またはエラーに適用されない場合、エラーの原因になったトランザクションはエラー・キューに移動されます。

10.9 XStream In構成内のコンポーネントの削除

DBMS_XSTREAM_ADMパッケージのDROP_INBOUNDプロシージャを使用して、インバウンド・サーバーを削除できます。

このプロシージャは、指定されたインバウンド・サーバーを常に削除します。また、次の条件が両方満たされている場合、このプロシージャはインバウンド・サーバーのキューも削除します。

  • CREATE_INBOUNDプロシージャへの1回のコールによって、インバウンド・サーバーおよびキューが作成されている。

  • インバウンド・サーバーがこのキューの唯一のサブスクライバである。

前述の条件のいずれかが満たされていない場合、DROP_INBOUNDプロシージャはインバウント・サーバーのみを削除します。キューは削除されません。

インバウンド・サーバーを削除するには、次のようにします。

  1. インバウンド・サーバー・データベースにXStream管理者として接続します。

    SQL*Plusでのデータベースへの接続の詳細は、Oracle Database管理者ガイドを参照してください。

  2. DROP_INBOUNDプロシージャを実行します。

インバウンド・サーバーのキューが自動的に削除されない場合、REMOVE_QUEUEプロシージャを実行してキューを削除します。

例10-12 インバウンド・サーバーの削除

xinという名前のインバウンド・サーバーを削除するには、次の手順を実行します。

exec DBMS_XSTREAM_ADM.DROP_INBOUND('xin');

例10-13 インバウンド・サーバーのキューの削除

xin_queueという名前のキューを削除するには、次のプロシージャを実行します。

exec DBMS_XSTREAM_ADM.REMOVE_QUEUE('xin_queue');