ヘッダーをスキップ
Oracle® Streamsレプリケーション管理者ガイド
12cリリース1 (12.1)
B71328-02
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

9 Oracle Streamsの競合解消

一部のOracle Streams環境では、複数のデータベース間にデータ共有が原因で発生する可能性のあるデータの競合を解消するために、競合ハンドラを使用する必要があります。

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

Oracle Streams環境内のDMLの競合

競合は、LCR内の古い値と、表内の予期されるデータが一致しないことです。複数データベース上で同じデータに対して同時のデータ操作言語(DML)操作を許可しているOracle Streams環境では、競合が発生する可能性があります。Oracle Streams環境でDMLの競合が発生する可能性があるのは、適用プロセスがDML操作によって生じる行の変更を含むメッセージを適用している場合のみです。この種のメッセージは、行の論理変更レコードまたは行LCRと呼ばれます。適用プロセスでは、行LCRが原因で発生する競合が自動的に検出されます。

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

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


注意:

適用プロセスでは、DDLの競合またはユーザー・メッセージによって発生する競合は検出されません。この種の競合が環境で防止されることを確認してください。


関連項目:

行LCRの詳細は、『Oracle Streams概要および管理』を参照してください。

Oracle Streams環境内の競合のタイプ

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

Oracle Streams環境内の更新の競合

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

Oracle Streams環境内の一意性競合

一意性競合が発生するのは、適用プロセスで適用される行LCRに含まれている行の変更が、PRIMARY KEY制約やUNIQUE制約など、一意性の整合性制約に違反している場合です。たとえば、2つの異なるデータベースからの2つのトランザクションがあり、それぞれのトランザクションが同じ主キー値を持つ表に1行を挿入する場合を考えます。この場合は、これらのトランザクションによって一意性競合が発生します。

Oracle Streams環境内の削除の競合

削除の競合が発生するのは、異なるデータベースで発生した2つのトランザクションがあり、1つのトランザクションで1行を削除し、もう1つのトランザクションで同じ行を更新または削除する場合です。この場合、行LCR内で参照された行は存在せず、更新も削除もできません。

Oracle Streams環境内の外部キーの競合

外部キーの競合が発生するのは、適用プロセスで適用される行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の部門の行が存在しないため、外部キーの競合が発生します。

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

Oracle Streams環境では、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で、1つの適用プロセスは、別の適用プロセスがmult3.example.commult1.example.comから変更の適用を実施する前に、mult2.example.comから変更の適用を試みます。

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

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

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

Oracle Streams環境内の競合検出

適用プロセスでは、更新、一意性、削除および外部キーの競合が次のように検出されます。

  • 行LCR内の行の元の値と、宛先データベースにある同じ行の現行の値が一致しない場合は、適用プロセスによって更新の競合が検出されます。

  • 挿入または更新操作を含むLCRの適用時に一意制約違反が発生すると、適用プロセスによって一意性競合が検出されます。

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

  • LCRの適用時に外部キー制約違反が発生すると、適用プロセスによって外部キーの競合が検出されます。

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


注意:

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

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


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

デフォルトでは、適用プロセスは競合検出中にすべての列の古い値を比較しますが、DBMS_APPLY_ADMパッケージのCOMPARE_OLD_VALUESプロシージャを使用すると、非キー列の競合検出を停止できます。競合検出は、一部の非キー列では不要な場合があります。

Oracle Streams環境内の競合検出中の行の識別

Oracleは、競合を正確に検出するために、異なるデータベースで対応する行を一意に識別して一致させることができる必要があります。デフォルトでは、Oracleは表の主キーを使用してその表の各行を一意に識別します。表に主キーが存在しない場合は、代替キーを指定する必要があります。代替キーとは、Oracleが表の各行を一意に識別するために使用できる列または列セットです。


関連項目:

『Oracle Streams概要および管理』

Oracle Streams環境内の競合防止

この項では、データ競合を防止する方法について説明します。

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

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

特定タイプの競合の防止

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

Oracle Streams環境内の一意性競合の防止

各データベースで共有データに一意識別子を使用させることで、一意性競合を回避できます。Oracle Streams環境ですべてのデータベースに一意識別子を確実に使用させるには、3つの方法があります。

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

SELECT SYS_GUID() OID FROM DUAL;

このSQL演算子は、16バイトのグローバル一意識別子を戻します。この値は、グローバル一意識別子を生成するために時刻、日付およびコンピュータ識別子を使用するアルゴリズムに基づいています。グローバル一意識別子は、次のような書式で表示されます。

A741C791252B3EA0E034080020AE3E0A

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

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

表9-1 Oracle Streamsレプリケーション環境用にカスタマイズされた順序

パラメータ データベース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を指定して、各データベースに異なる範囲を定義できます。

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

共有データ環境では、削除の競合を必ず回避してください。通常、共有所有権データ・モデル内で動作するアプリケーションでは、DELETE文を使用して行を削除することはありません。かわりに、アプリケーションで行に削除マークを付けておき、論理的に削除された行を定期的にパージするようにシステムを構成する必要があります。

Oracle Streams環境内の更新の競合の防止

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

Oracle Streams環境内の競合解消

更新の競合が検出された場合、競合ハンドラではその解消を試みることができます。Oracle Streamsには、更新の競合を解消するためのビルトイン競合ハンドラが用意されていますが、一意性、削除、外部キーまたは順序付けの競合については用意されていません。ただし、ビジネス・ルールに固有のデータ競合を解消するために、独自のカスタム競合ハンドラを作成できます。この種の競合ハンドラは、プロシージャDMLハンドラまたはエラー・ハンドラに付属させることができます。

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

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


関連項目:

  • プロシージャDMLハンドラ、エラー・ハンドラおよびエラー・キューの詳細は、『Oracle Streams概要および管理』を参照してください。

  • DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。


ビルトインの更新の競合ハンドラ

この項では、使用可能なビルトインの更新の競合ハンドラのタイプと、この種のハンドラでの列リストと解消列の使用方法について説明します。列リストは、更新の競合がある場合に更新の競合ハンドラがコールされる列のリストです。解消列は、更新の競合ハンドラの識別に使用される列です。ビルトインの更新の競合ハンドラMAXIMUMまたはMINIMUMを使用する場合は、解消列も競合の解消に使用されます。解消列は、ハンドラの列リスト内の列の1つである必要があります。

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


関連項目:


ビルトインの更新の競合ハンドラのタイプ

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

後述の各タイプのハンドラの説明では、次の競合例を参照しています。

  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)と一致しないため、競合が発生します。

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

OVERWRITE

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

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

DISCARD

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

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

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回起動に設定されていることを確認してください。設定が異なると、適用プロセスによってトランザクションが適用されるときに新規時刻がマークされ、トランザクションの実際時刻が失われる可能性があります。


関連項目:

『Oracle Streams概要および管理』

MINIMUM

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

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

列リスト

表に対してビルトインの更新の競合ハンドラを指定するたびに、列リストを指定する必要があります。列リストは、更新の競合ハンドラがコールされる列のリストです。適用プロセスが行LCRを適用するときに、リスト内の1つ以上の列に更新の競合が発生すると、競合を解消するために更新の競合ハンドラがコールされます。リストにない列にのみ競合が発生した場合、更新の競合ハンドラはコールされません。競合解消の有効範囲は、1つの行LCRの1つの列リストです。

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

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

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

また、この表に他の競合ハンドラは存在しないものと想定します。この場合、適用プロセスが行LCRを適用するときにsalary列に競合が発生すると、それを解消するために最初の更新の競合ハンドラがコールされます。ただし、department_id列に競合が発生すると、それを解消するために2番目の更新の競合ハンドラがコールされます。どの競合ハンドラの列リストにもない列に競合が発生すると、競合ハンドラはコールされず、エラーになります。この例では、hr.employees表のmanager_id列に競合が発生すると、エラーになります。行LCRの適用時に複数の列リストに競合が発生し、列リストにない列での競合がなければ、競合が発生した列リストごとに適切な更新の競合ハンドラが起動されます。

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

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

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

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

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

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


注意:

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


関連項目:


解消列

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

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

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

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

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


注意:

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

データ収束

複数のデータベース間でデータを共有しており、そのすべてでデータを同一にする必要がある場合は、すべてのデータベースでデータを収束させる競合解消ハンドラを使用してください。すべてのデータベースで共有データの変更を許可する場合、表のデータ収束が可能になるのは、データを共有する全データベースが共有データに対する変更を取得し、データを共有する他のすべてのデータベースにその変更を伝播する場合のみです。

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

カスタム競合ハンドラ

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

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

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

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

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


関連項目:

  • エラー・ハンドラの管理の詳細は、『Oracle Streams概要および管理』を参照してください。

  • SET_DML_HANDLERプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。


Oracle Streamsの競合検出および解消の管理

この項では、次のタスクについて説明します。

更新の競合ハンドラの設定

更新の競合ハンドラを設定するには、DBMS_APPLY_ADMパッケージのSET_UPDATE_CONFLICT_HANDLERプロシージャを使用します。更新の競合解消ハンドラを作成する場合は、次のいずれかの事前作成方法を使用できます。

  • OVERWRITE

  • DISCARD

  • MAXIMUM

  • MINIMUM

たとえば、Oracle Streams環境のdbs1.example.comhr.jobs表に対する変更を取得して、dbs2.example.com宛先データベースに伝播し、そこで適用する場合を考えます。この環境の場合、アプリケーションでは両方のデータベースのhr.jobs表に対してDML変更を実行できますが、特定のDML変更に競合がある場合は、dbs1.example.comデータベースでの変更でdbs2.example.comデータベースでの変更を常に上書きする必要があります。この環境では、dbs2.example.comデータベースでOVERWRITEハンドラを指定して、この目標を達成できます。

dbs2.example.comデータベースでhrスキーマ内のhr.jobs表について更新の競合ハンドラを指定するには、dbs2.example.comで次のプロシージャを実行します。

DECLARE
  cols DBMS_UTILITY.NAME_ARRAY;
  BEGIN
    cols(1) := 'job_title';
    cols(2) := 'min_salary';
    cols(3) := 'max_salary';
    DBMS_APPLY_ADM.SET_UPDATE_CONFLICT_HANDLER(
      object_name       => 'hr.jobs',
      method_name       => 'OVERWRITE',
      resolution_column => 'job_title',
      column_list       => cols);
END;
/

データベース上で実行中の、指定の表に変更を適用するすべての適用プロセスでは、指定した更新の競合ハンドラがローカルに使用されます。


注意:

  • OVERWRITEおよびDISCARDメソッドにはresolution_columnは使用されませんが、column_list内の列の1つは指定する必要があります。

  • 宛先データベースのcolumn_listにあるすべての列について、ソース・データベースで条件付きのサプリメンタル・ログ・グループを指定する必要があります。この例では、dbs1.example.comデータベースのhr.jobs表のjob_titlemin_salaryおよびmax_salary列を含む条件付きのサプリメンタル・ログ・グループを指定します。

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



関連項目:

  • 「サプリメンタル・ロギングの指定」

  • 時間ベースの競合解消にMAXIMUM事前作成方法を使用するOracle Streams環境の例については、『Oracle Streams拡張例』を参照してください。

  • データ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。


既存の更新の競合ハンドラの変更

DBMS_APPLY_ADMパッケージのSET_UPDATE_CONFLICT_HANDLERプロシージャを実行すると、既存の更新の競合ハンドラを変更できます。既存の競合ハンドラを更新するには、そのハンドラと同じ表および解消列を指定します。

「更新の競合ハンドラの設定」で作成した更新の競合ハンドラを変更するには、hr.jobs表および解消列としてのjob_title列を指定します。この更新の競合ハンドラを変更するには、異なるタイプの事前作成方法または異なる列リスト、あるいはその両方を指定できます。ただし、更新の競合ハンドラの解消列を変更するには、ハンドラを削除して再作成する必要があります。

たとえば、環境に変更があり、競合が発生した場合にdbs1.example.comからの変更を廃棄する必要があるが、dbs1.example.comからの以前の変更によってdbs2.example.comの変更が上書きされている場合を考えます。dbs2.example.comデータベースでDISCARDハンドラを指定すると、この目標を達成できます。

dbs2.example.comデータベースでhrスキーマ内のhr.jobs表について既存の更新の競合ハンドラを変更するには、次のプロシージャを実行します。

DECLARE
  cols DBMS_UTILITY.NAME_ARRAY;
  BEGIN
    cols(1) := 'job_title';
    cols(2) := 'min_salary';
    cols(3) := 'max_salary';
    DBMS_APPLY_ADM.SET_UPDATE_CONFLICT_HANDLER(
      object_name       => 'hr.jobs',
      method_name       => 'DISCARD',
      resolution_column => 'job_title',
      column_list       => cols);
END;
/

既存の更新の競合ハンドラの削除

DBMS_APPLY_ADMパッケージのSET_UPDATE_CONFLICT_HANDLERプロシージャを実行すると、既存の更新の競合ハンドラを削除できます。既存の競合ハンドラを削除するには、メソッドにNULLを指定し、その競合ハンドラと同じ表、列リストおよび解消列を指定します。

たとえば、「更新の競合ハンドラの設定」で作成し、「既存の更新の競合ハンドラの変更」で変更した更新の競合ハンドラを削除する必要があるとします。この更新の競合ハンドラを削除するには、次のプロシージャを実行します。

DECLARE
  cols DBMS_UTILITY.NAME_ARRAY;
  BEGIN
    cols(1) := 'job_title';
    cols(2) := 'min_salary';
    cols(3) := 'max_salary';
    DBMS_APPLY_ADM.SET_UPDATE_CONFLICT_HANDLER(
      object_name       => 'hr.jobs',
      method_name       => NULL,
      resolution_column => 'job_title',
      column_list       => cols);
END;
/

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

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

たとえば、hr.employees表の競合解消用にtime列を構成すると想定します(「MAXIMUM」を参照)。この場合、表の他の非キー列の競合検出を停止するように指定できます。これを行うには、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_UPDATE_CONFLICT_HANDLER(
    object_name       => 'hr.employees',
    method_name       => 'MAXIMUM',
    resolution_column => 'time',
    column_list       => cols);
END;
/

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

宛先データベースでUPDATEおよびDELETE操作の両方を行う表のすべての非キー列について、競合検出を停止するには、次のプロシージャを実行します。

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およびDELETE操作の両方について競合検出が停止されたことを意味します。このプロシージャを実行すると、データベース上で実行中の、指定の表に変更をローカルに適用するすべての適用プロセスでは、指定した列の競合は検出されません。したがって、この例では、time列のみが競合検出に使用されます。


注意:

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


関連項目:


競合検出および更新の競合ハンドラの監視

ここでは、Streamsレプリケーション環境で適用プロセスを監視するために実行できる問合せについて説明します。


関連項目:

『Oracle Streams概要および管理』

競合検出に関する情報の表示

DBMS_APPLY_ADMパッケージのCOMPARE_OLD_VALUESプロシージャを使用すると、非キー列の競合検出を停止できます。このプロシージャを使用すると、宛先データベースのすべての適用プロセスについて、指定した列の更新および削除の競合検出が停止されます。競合検出が停止された各列を表示するには、次の問合せを実行します。

COLUMN OBJECT_OWNER HEADING 'Table Owner' FORMAT A15
COLUMN OBJECT_NAME HEADING 'Table Name' FORMAT A20
COLUMN COLUMN_NAME HEADING 'Column Name' FORMAT A20
COLUMN COMPARE_OLD_ON_DELETE HEADING 'Compare|Old On|Delete' FORMAT A7
COLUMN COMPARE_OLD_ON_UPDATE HEADING 'Compare|Old On|Update' FORMAT A7

SELECT OBJECT_OWNER, 
       OBJECT_NAME, 
       COLUMN_NAME, 
       COMPARE_OLD_ON_DELETE, 
       COMPARE_OLD_ON_UPDATE 
  FROM DBA_APPLY_TABLE_COLUMNS
  WHERE APPLY_DATABASE_LINK IS NULL;

出力は次のようになります。

                                                          Compare Compare
                                                          Old On  Old On
Table Owner     Table Name           Column Name          Delete  Update
--------------- -------------------- -------------------- ------- -------
HR              EMPLOYEES            COMMISSION_PCT       NO      NO
HR              EMPLOYEES            EMAIL                NO      NO
HR              EMPLOYEES            FIRST_NAME           NO      NO
HR              EMPLOYEES            HIRE_DATE            NO      NO
HR              EMPLOYEES            JOB_ID               NO      NO
HR              EMPLOYEES            LAST_NAME            NO      NO
HR              EMPLOYEES            PHONE_NUMBER         NO      NO
HR              EMPLOYEES            SALARY               NO      NO


注意:

Oracle以外のリモート・データベースに適用される変更についての競合検出を停止することもできます。この問合せでは、APPLY_DATABASE_LINK列がNULLの場合にのみ指定が表示されるため、このような指定は表示されません。

更新の競合ハンドラに関する情報の表示

DBMS_APPLY_ADMパッケージのSET_UPDATE_CONFLICT_HANDLERプロシージャを使用して更新の競合ハンドラを指定した場合は、関連する競合が発生すると、そのハンドラがデータベース内のすべての適用プロセスに対して実行されます。

この項で説明する問合せを実行すると、ビルトインの更新の競合ハンドラを使用して競合解消が指定されている列がすべて表示されます。つまり、データベース内で指定されているすべての列リストの列が表示されます。また、この問合せでは、指定されているビルトインの競合ハンドラの型と、列リストに指定されている解消列も表示されます。

データベース内のすべての更新の競合ハンドラに関する情報を表示するには、次の問合せを実行します。

COLUMN OBJECT_OWNER HEADING 'Table|Owner' FORMAT A5
COLUMN OBJECT_NAME HEADING 'Table Name' FORMAT A12
COLUMN METHOD_NAME HEADING 'Method' FORMAT A12
COLUMN RESOLUTION_COLUMN HEADING 'Resolution|Column' FORMAT A13
COLUMN COLUMN_NAME HEADING 'Column Name' FORMAT A30

SELECT OBJECT_OWNER, 
       OBJECT_NAME, 
       METHOD_NAME, 
       RESOLUTION_COLUMN, 
       COLUMN_NAME
  FROM DBA_APPLY_CONFLICT_COLUMNS
  ORDER BY OBJECT_OWNER, OBJECT_NAME, RESOLUTION_COLUMN;

出力は次のようになります。

Table                           Resolution
Owner Table Name   Method       Column        Column Name
----- ------------ ------------ ------------- ------------------------------
HR    COUNTRIES    MAXIMUM      TIME          COUNTRY_NAME
HR    COUNTRIES    MAXIMUM      TIME          REGION_ID
HR    COUNTRIES    MAXIMUM      TIME          TIME
HR    DEPARTMENTS  MAXIMUM      TIME          DEPARTMENT_NAME
HR    DEPARTMENTS  MAXIMUM      TIME          LOCATION_ID
HR    DEPARTMENTS  MAXIMUM      TIME          MANAGER_ID
HR    DEPARTMENTS  MAXIMUM      TIME          TIME