この付録では、ユーザー定義の競合解消メソッドおよびユーザー定義の競合通知方法の作成方法を説明します。
この付録では、次の項目を説明します。
ユーザー独自の競合解消メソッドや通知方法を作成できます。ユーザー定義の競合解消メソッドとは、TRUEまたはFALSEのいずれかを戻すPL/SQLファンクションです。TRUEは、列グループへの競合する変更すべてが競合解消メソッドによって正常に解消されたことを示します。競合が正常に解消されない場合は、FALSEが戻されます。競合解消メソッドからTRUEが戻されるか、または使用可能な競合解消メソッドがなくなるまで、方法の評価が順番に続行されます。
競合解消メソッドで例外が呼び出されると、その方法の評価が停止します。それ以降の順序番号でその他の競合解消メソッドが用意されていても、評価は行われません。
ユーザー定義の競合解消メソッドで必要なパラメータは、解消する競合のタイプ(一意、更新または削除)およびレプリケートされる表の列によって決定されます。すべての競合解消メソッドは、表の古い列値、新しい列値およびカレント列値の組合せを使用します。
古い値は、発信元サイトでの変更前の行の値を表します。
新しい値は、発信元サイトでの変更後の行の値を表します。
カレント値は、受信サイトでの対応する行の値を表します。
|
注意: Oracleでは、比較する行の判別に、主キー、すなわち |
競合解消機能は、DBMS_REPCAT.ADD_conflicttype_RESOLUTIONプロシージャに対するPARAMETER_COLUMN_NAME引数で指定した列値をパラメータとして受け取ります。列パラメータは、PARAMETER_COLUMN_NAME引数に示される順序で、またこの引数に'*'を指定した場合はアルファベットの昇順で、競合解消メソッドに渡されます。古い列値と新しい列値の両方が(更新の競合の)パラメータとして渡される場合、列の古い値は新しい値の直前に置かれます。
更新の競合の場合、ユーザー定義ファンクションでは、列グループ内の各列に次の値を使用する必要があります。
発信元サイトからの古い列値。このパラメータのモードはINです。この値は変更できません。
発信元サイトからの新しい列値。このパラメータのモードはIN OUTです。そのファンクションで競合を正常に解消できる場合は、必要に応じて新しい列値を変更する必要があります。
受信サイトからのカレント列値。このパラメータのモードは INです。
列値は、古い値、新しい値、カレント値と連続して受信されます。競合解消メソッドに渡す最後の引数は、ブール型フラグである必要があります。このフラグがFALSEの場合、IN OUTパラメータ(すなわち、新しい列)の値をすでに更新したこと、およびカレント列値をこの新しい値に更新する必要があることを示します。このフラグがTRUEの場合、カレント列値を変更できないことを示します。
一意性競合は、INSERTまたはUPDATEの結果として発生する場合があります。ユーザー定義の一意性競合解消メソッドでは、列グループの各列に、発信元サイトからのIN OUTモードの新しい列値を受け入れる必要があります。競合解消メソッドに渡す最後のパラメータは、ブール型フラグである必要があります。
競合解消メソッドで競合が解消された場合、新しい列値を変更して、現在行への挿入または現在行の新しい列値による更新を可能にします。ファンクションにより新しい列値を廃棄する場合はブール型フラグをTRUEに設定し、廃棄しない場合はFALSEに設定します。
競合解消メソッドでは一意性競合におけるデータの収束を保証できないので、ユーザー定義の一意性競合解消メソッドに通知メカニズムを組み込む必要があります。
削除の競合は、ローカル・サイトからの削除が正常に実行されても、対応付けられた行が(更新されたなどの理由で)リモート・サイトにない場合に発生します。削除の競合の場合、ファンクションでは、行全体の古い列値をIN OUTモードで受け入れる必要があります。競合解消メソッドに渡す最後のパラメータは、ブール型フラグである必要があります。
競合解消メソッドで競合が解消されると、古い列値が変更され、すべての古い列値に一致する現在行を削除できます。ファンクションによりこれらの列値を廃棄する場合はブール型フラグをTRUEに設定し、廃棄しない場合はFALSEに設定します。
ローカル・サイトで削除を実行し、リモート・サイトで更新を実行した場合、リモート・サイトで削除の競合が検出されますが、ローカル・サイトでは解消不可能な更新の競合が検出されます。このタイプの競合は自動的には処理できません。この競合によってNO_DATA_FOUND例外が発生し、このトランザクションはエラー・トランザクションとして記録されます。
これらのタイプの更新や削除の競合を適切に処理するメカニズムを設計することは困難です。削除された行を単純にマーク付けして、プロシージャ・レプリケーションを使用してパージすることで、これらのタイプの競合を完全に回避するほうがはるかに容易です。
ユーザー定義の競合解消メソッドを複数層マテリアライズド・ビューに使用するときは、これらの方法に関する情報はマスター・マテリアライズド・ビュー・サイトに自動的にプルダウンされます。この情報は、マスター・マテリアライズド・ビュー・サイトのデータ・ディクショナリに格納されます。ただし、ユーザー定義の競合解消メソッドそのものをマスター・サイトからプルダウンすることはできません。このため、マスター・マテリアライズド・ビュー・サイトでこれらの方法を再作成する必要があります。
|
関連項目:
|
次の項では、ユーザー定義の競合解消メソッドの制限事項を説明します。
ユーザー定義の競合解消メソッドで次のSQL文を使用しないでください。これらの文を使用すると、予期しない結果が起こる可能性があります。
データ定義言語(DDL)文(CREATE、ALTER、DROPなど)
トランザクション制御文(COMMIT、ROLLBACKなど)
セッション制御(ALTER SESSIONなど)
システム制御(ALTER SYSTEMなど)
更新可能な複数層マテリアライズド・ビューを作成するときは、列グループの列をサブセット化しないでください。列をサブセット化すると、マスター表またはマスター・マテリアライズド・ビューの列が、これらのマスターをベースとするマテリアライズド・ビューから除外されます。これを行うには、マテリアライズド・ビューの作成中にSELECT文でいくつかのSELECT列を指定します。
競合解消を複数層マテリアライズド・ビューに使用するときは、マテリアライズド・ビュー・サイトでは競合解消メソッドを定義できません。競合解消メソッドは、常にマスター・サイトからプルダウンされます。このため、ユーザー定義の競合解消を持つ列グループの列をサブセット化すると、マスター・マテリアライズド・ビュー・サイトの列グループの列をすべてこの競合解消メソッドで見つけることができなくなります。この場合、競合解消メソッドから次のエラーが戻されます。
ORA-23460 missing value for column in resolution method
たとえば、hr.employees表のjob_id、salaryおよびcommission_pct列が、マスター・サイトhq.example.comにある、ユーザー定義の競合解消メソッドを持つ列グループ名employees_cg1の一部である場合を考えます。営業スタッフのプライバシーを保護するため、列サブセット化を使用してca.usオフィスのsalaryおよびcommission_pct列を排除する、レベル1の更新可能なマテリアライズド・ビューを作成します。 ca.usオフィスにこのマテリアライズド・ビューを作成すると、競合解消メソッドがhq.example.comからプルダウンされます。次に、sf.caオフィスに、ca.usオフィスのレベル1のマテリアライズド・ビューをベースとする更新可能なマテリアライズド・ビューを作成します。
このレプリケーション環境では、ca.usオフィスのレベル 1のマテリアライズド・ビューでjob_id値の競合が発生した場合、競合解消メソッドではsalaryおよびcommission_pct列が見つけられず、前述のORA-23460エラーが戻されます。
|
関連項目: 列サブセット化の詳細は、『Oracle Databaseアドバンスト・レプリケーション』を参照してください。 |
標準的な組込みの最大値および加算による競合解消メソッドを変形した、ユーザー定義方法の例を次に示します。標準方法と異なり、これらのユーザー定義ファンクションでは、競合解消に使用される列内のNULL値を処理できます。
-- User function similar to MAXIMUM method.
-- If curr is null or curr < new, then use new values.
-- If new is null or new < curr, then use current values.
-- If both are null, then no resolution.
-- Does not converge with > 2 masters, unless
-- always increasing.
CREATE OR REPLACE FUNCTION max_null_loses(old IN NUMBER,
new IN OUT NUMBER,
cur IN NUMBER,
ignore_discard_flag OUT BOOLEAN)
RETURN BOOLEAN IS
BEGIN
IF (new IS NULL AND cur IS NULL) OR new = cur THEN
RETURN FALSE;
END IF;
IF new IS NULL THEN
ignore_discard_flag := TRUE;
ELSIF cur IS NULL THEN
ignore_discard_flag := FALSE;
ELSIF new < cur THEN
ignore_discard_flag := TRUE;
ELSE
ignore_discard_flag := FALSE;
END IF;
RETURN TRUE;
END max_null_loses;
/
-- User function similar to ADDITIVE method.
-- If old is null, then old = 0.
-- If new is null, then new = 0.
-- If curr is null, then curr = 0.
-- new = curr + (new - old) -> just like ADDITIVE method.
CREATE OR REPLACE FUNCTION additive_nulls(old IN NUMBER,
new IN OUT NUMBER,
cur IN NUMBER,
ignore_discard_flag OUT BOOLEAN)
RETURN BOOLEAN IS
old_val NUMBER := 0.0;
new_val NUMBER := 0.0;
cur_val NUMBER := 0.0;
BEGIN
IF old IS NOT NULL THEN
old_val := old;
END IF;
IF new IS NOT NULL THEN
new_val := new;
END IF;
IF cur IS NOT NULL THEN
cur_val := cur;
END IF;
new := cur_val + (new_val - old_val);
ignore_discard_flag := FALSE;
RETURN TRUE;
END additive_nulls;
/
競合通知方法は、競合解消のかわりまたは追加として競合を通知する、ユーザー定義ファンクションです。たとえば、独自の競合通知方法を作成して、データベース表に競合情報を記録したり、電子メール・メッセージを送信したり、管理者を呼び出したりできます。競合通知方法を作成した後、それを列グループ(または制約)に特定の順序で割り当てて、競合が発生した時点か、後続の競合解消メソッドを試行する前か、競合解消を試行して失敗した後に、通知を受けることができます。
レプリケート表にユーザー定義の競合通知メカニズムを構成するには、次の手順を実行する必要があります。
競合通知ログを作成します。
パッケージ内にユーザー定義の競合通知方法を作成します。
次の項で各手順を説明します。
ユーザー定義の競合通知方法を使用するレプリケート表を構成するときは、最初に、競合通知を記録できるデータベース表を作成します。マスター・グループ内の1つ以上の表での競合通知を記録するデータベース表を作成できます。
すべてのマスター・サイトで競合通知ログ表を作成するには、レプリケーション実行DDL機能を使用します。詳細は、「EXECUTE_DDLプロシージャ」を参照してください。競合通知表のエントリは競合を検出するサイトに固有のエントリであるため、競合通知表に対するレプリケーション・サポートを生成しないでください。
次のCREATE TABLE文では、マスター・グループのいくつかの表から競合通知を記録するのに使用する表を作成します。
CREATE TABLE sales.conf_report (
line NUMBER(2), --- used to order message text
txt VARCHAR2(80), --- conflict notification message
timestamp DATE, --- time of conflict
table_name VARCHAR2(30), --- table in which the
--- conflict occurred
table_owner VARCHAR2(30), --- owner of the table
conflict_type VARCHAR2(6) --- INSERT, DELETE or UNIQUE
);
競合通知方法を作成するには、PL/SQLパッケージ内で方法を定義し、対応付けられたレプリケート表とともにPL/SQLパッケージをマスター・グループの一部としてレプリケートする必要があります。
競合通知方法では、競合の通知のみ、または競合の通知と解消の両方を実行できます。可能な場合は常に、Oracleの組込み競合解消メソッドのいずれかを使用して競合を解消する必要があります。ユーザー定義の競合通知方法で競合の通知のみを実行する場合は、競合を解消する競合解消メソッドとともに、ユーザー定義の通知方法を列グループ(または制約)に割り当ててください。
|
注意: レプリケーションの競合が最終的に解消されない場合は、通知表に加えられた更新内容を含め、トランザクション全体がロールバックされます。トランザクションとは無関係に通知が必要な場合は、Oracle |
次のパッケージおよびパッケージ本体では、CUSTOMERS表の一意性競合を定義済のCONF_REPORT表に記録することによって、簡単な競合通知を実行します。
|
注意: この競合通知の例では、競合は解消されません。したがって、競合解消メソッド(廃棄や上書きなど)を用意するか、エラーが解消されずにトランザクションがロールバックされても正しく機能する通知メカニズム(電子メールの利用など)を用意する必要があります。次のユーザー定義の競合通知方法に簡単な変更を加えれば、さらに有効な処置を取ることができます。たとえば、このパッケージでは、通知メッセージを記録でき、また |
CREATE OR REPLACE PACKAGE notify AS
-- Report uniqueness constraint violations on CUSTOMERS table
FUNCTION customers_unique_violation (
first_name IN OUT VARCHAR2,
last_name IN OUT VARCHAR2,
discard_new_values IN OUT BOOLEAN)
RETURN BOOLEAN;
END notify;
/
CREATE OR REPLACE PACKAGE BODY notify AS
-- Define a PL/SQL index-by table to hold the notification message
TYPE message_table IS TABLE OF VARCHAR2(80) INDEX BY BINARY_INTEGER;
PROCEDURE report_conflict (
conflict_report IN MESSAGE_TABLE,
report_length IN NUMBER,
conflict_time IN DATE,
conflict_table IN VARCHAR2,
table_owner IN VARCHAR2,
conflict_type IN VARCHAR2) IS
BEGIN
FOR idx IN 1..report_length LOOP
BEGIN
INSERT INTO sales.conf_report
(line, txt, timestamp, table_name, table_owner, conflict_type)
VALUES (idx, SUBSTR(conflict_report(idx),1,80), conflict_time,
conflict_table, table_owner, conflict_type);
EXCEPTION WHEN others THEN NULL;
END;
END LOOP;
END report_conflict;
-- This is the conflict resolution method that is called first when
-- a uniqueness constraint violated is detected in the CUSTOMERS table.
FUNCTION customers_unique_violation (
first_name IN OUT VARCHAR2,
last_name IN OUT VARCHAR2,
discard_new_values IN OUT BOOLEAN)
RETURN BOOLEAN IS
local_node VARCHAR2(128);
conf_report MESSAGE_TABLE;
conf_time DATE := SYSDATE;
BEGIN
-- Get the global name of the local site
BEGIN
SELECT global_name INTO local_node FROM global_name;
EXCEPTION WHEN others THEN local_node := '?';
END;
-- Generate a message for the DBA
conf_report(1) := 'UNIQUENESS CONFLICT DETECTED IN TABLE CUSTOMERS ON ' ||
TO_CHAR(conf_time, 'MM-DD-YYYY HH24:MI:SS');
conf_report(2) := ' AT NODE ' || local_node;
conf_report(3) := 'ATTEMPTING TO RESOLVE CONFLICT USING ' ||
'APPEND SEQUENCE METHOD';
conf_report(4) := 'FIRST NAME: ' || first_name;
conf_report(5) := 'LAST NAME: ' || last_name;
conf_report(6) := NULL;
--- Report the conflict
report_conflict(conf_report, 5, conf_time, 'CUSTOMERS',
'OFF_SHORE_ACCOUNTS', 'UNIQUE');
--- Do not discard the new column values. They are still needed by
--- other conflict resolution methods.
discard_new_values := FALSE;
--- Indicate that the conflict was not resolved.
RETURN FALSE;
END customers_unique_violation;
END notify;
/
Oracleには、レプリケーション・カタログ(REPCAT)ビューが用意されており、このビューを使用して、レプリケーション環境の各表および列グループで使用している競合解消メソッドを判別できます。各ビューには、USER_*、ALL_*、SYS.DBA_*の3つのバージョンがあります。使用可能なビューを次の表に示します。
| ビュー | 説明 |
|---|---|
| ALL_REPRESOLUTION_METHOD | 使用可能な競合解消メソッドがすべて表示されます。 |
| ALL_REPCOLUMN_GROUP | データベースに定義された列グループがすべて表示されます。 |
| ALL_REPGROUPED_COLUMN | データベース内の各列グループの列がすべて表示されます。 |
| ALL_REPPRIORITY_GROUP | データベースに定義された優先グループおよびサイト優先グループがすべて表示されます。 |
| ALL_REPPRIORITY | 各優先グループまたはサイト優先グループの値および対応する優先順位レベルが表示されます。 |
| ALL_REPCONFLICT | データベース内の表、列グループおよび一意制約に関して解決メソッドを指定した競合のタイプ(削除、更新または一意性)が表示されます。 |
| ALL_REPRESOLUTION | 各オブジェクトで発生する競合解消メソッドに関する、より具体的な情報が表示されます。 |
| ALL_REPPARAMETER_COLUMN | 競合解消メソッドが競合の解消に使用する列が表示されます。 |