手动冲突检测和解决

了解如何使用特定参数手动配置冲突检测和解决 (Conflict Detection and Resolution,CDR)。在主动 - 主动配置中,需要进行冲突检测和解决,Oracle GoldenGate 必须在包含相同数据集的多个数据库之间保持数据同步。

Oracle GoldenGate CDR 功能概览

Oracle GoldenGate 冲突检测和解决 (Conflict Detection and Resolution,CDR) 有两个部分:冲突检测和冲突解决。在开始解决冲突之前,必须进行调查并完成冲突检测。

Oracle GoldenGate 冲突检测和解决 (Conflict Detection and Resolution,CDR) 提供以下基本冲突解决例程:

要使用冲突检测和解决 (CDR),目标数据库必须位于 Windows、Linux 或 UNIX 系统上。NonStop 平台上的数据库不支持该功能。

CDR 支持标量数据类型,例如:

这意味着这些列类型可以与 COMPARECOLS 参数一起使用,也可以作为 RESOLVECONFLICT 参数的 USEMIN 和 USEMAX 选项中的解析列。只能将 NUMERIC 列用于 RESOLVECONFLICT 的 USEDELTA 选项。对于 USEMAX、USEMIN,仅支持 TIMESTAMP 和 NUMBER。

当 Replicat 在 BATCHSQL 模式下运行时,不会执行冲突解决。如果在 BATCHSQL 模式下发生冲突,Replicat 将恢复为 GROUPTRANSOPS 模式,然后恢复为单事务模式。冲突检测在所有三种模式中发生。

配置 Oracle GoldenGate 参数文件以解决冲突

以下参数是支持冲突检测和解决的必需参数。

  1. 在 Replicat 参数文件中,使用 MAP 参数的 COMPARECOLS 选项指定要与 Replicat WHERE 子句中的之前值一起使用的列。将前面值与目标数据库中的当前值进行比较,以检测更新和删除冲突。(默认情况下,复制仅使用 WHERE 子句中的主键;这可能不足以检测冲突)。

  2. 使用 MAP 参数的 RESOLVECONFLICT 选项为不同的操作和冲突类型指定冲突解决例程。可以在 MAP 语句中多次使用 RESOLVECONFLICT,以便为不同的冲突类型指定不同的解决方法。但是,不能多次将 RESOLVECONFLICT 用于同一类型的冲突。在所有数据库上使用相同的冲突解决过程,以便相同的冲突产生相同的最终结果。一种解决冲突的方法可能无法解决可能发生的每场冲突。您可能需要创建多个例程,这些例程可以按优先级的逻辑顺序进行调用,以便最大程度地降低失败的风险。

注:表具有主键和附加唯一索引或唯一键时,应考虑其他事项。随 COMPARECOLS 和 RESOLVECONFLICT 参数提供的自动化例程需要一种一致的方式来唯一标识每行。如果无法一致地标识行,则在解决冲突期间将导致错误。在这些情况下,应禁用其他唯一键,或者可以使用 SQLEXEC 功能来处理引发的错误并解决冲突。

有关这些参数的详细信息,请参阅 Parameters and Functions Reference for Oracle GoldenGate 。有关这些参数的更多信息,请参见 CDR Example 1:All Conflict Types with USEMAX,OVERWRITE,DISCARD 。

使必需的列值可供提取

要使用 CDR,必须记录以下列值,以便 Extract 可以将它们写入线索。

有关这些参数和命令的详细信息,请参见《 Parameters and Functions Reference for Oracle GoldenGate 》。有关这些参数如何与 CDR 配合使用的更多信息,请参见 CDR 示例 1:All Conflict Types with USEMAX,OVERWRITE,DISCARD 。

查看 CDR 统计信息

CDR 功能提供了以下方法来查看冲突解决结果。

下面是可用于查看 CDR 统计信息的不同技术。

报表文件

Replicat 将 CDR 统计信息写入到报告文件:

Total CDR conflicts        7
    CDR resolutions succeeded       6
    CDR resolutions failed          1
    CDR INSERTROWEXISTS conflicts   1
    CDR UPDATEROWEXISTS conflicts   4
    CDR UPDATEROWMISSING conflicts
    CDR DELETEROWEXISTS conflicts      1
    CDR DELETEROWMISSING conflicts     1

命令行

通过使用带有 REPORTCDR 选项的 STATS REPLICAT 命令,可以从命令行查看 CDR 统计信息:

STATS REPLICAT *group*, REPORTCDR

列转换函数

可以检索以下 CDR 统计信息并将其映射到异常表,也可以在接受列转换函数输入的其它 Oracle GoldenGate 参数中使用。

要检索这些统计信息,请将 @GETENV 列转换函数与 STATS 或 DELTASTATS 信息类型结合使用。结果基于当前复制会话。如果 Replicat 停止并重新启动,则会重置统计信息。

可以为特定表或一组通配符表返回这些统计信息:

@GETENV ('STATS','TABLE','SCHEMA.TABLNAME','CDR_CONFLICTS')
@GETENV ('STATS','TABLE','SCHEMA.TABLNAME','CDR_RESOLUTIONS_SUCCEEDED')
@GETENV ('STATS','TABLE','SCHEMA.TABLNAME','CDR_RESOLUTIONS_FAILED')

可以为复制参数文件中的所有 MAP 语句中的所有表返回这些统计信息:

@GETENV ('STATS','CDR_CONFLICTS')
@GETENV ('STATS','CDR_RESOLUTIONS_SUCCEEDED')
@GETENV ('STATS','CDR_RESOLUTIONS_FAILED')

上述示例中的 'STATS' 信息类型可以替换为 'DELTASTATS',以返回自上次执行 'DELTASTATS' 以来的请求计数。有关 @GETENV 的更多信息,请参见 @GETENV

CDR 示例 1:使用 USEMAX、OVERWRITE 和 DISCARD 的所有冲突类型

此示例通过使用 USEMAX、OVERWRITE 和 DISCARD 解析来解决所有冲突类型。

本示例中使用的表

这些示例假定相同的 Oracle 数据库。

CREATE TABLE hr.emp_tgt(
    name varchar2(30) primary key,
    phone varchar2(10),
    address varchar2(100),
    salary number,
    balance number,
    comment varchar2(100),
    last_mod_time timestamp);

在源数据库上,将补充记录所有列:

ADD TRANDATA hr.emp_src, COLS (name, phone, address, salary, balance, comment, last_mod_time);

具有冲突解决规范的 MAP 语句

MAP fin.src, TARGET fin.tgt,
    COMPARECOLS (ON UPDATE ALL, ON DELETE ALL),
    RESOLVECONFLICT (UPDATEROWEXISTS, (DEFAULT, USEMAX (last_mod_time)),
    RESOLVECONFLICT (INSERTROWEXISTS, (DEFAULT, USEMAX (last_mod_time)),
    RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, OVERWRITE)),
    RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)),
    RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD)),
    );

MAP 语句的说明

下面介绍了 MAP 语句:

INSERTROWEXISTS 与 USEMAX 解析

对于此示例,USEMAX 分辨率以线索和数据库中记录的适用图像之前和之后进行说明。它显示如何解析行存在于源和目标中的插入,但某些或所有行值不同。

表 10:INSERTROWEXISTS 与 USEMAX 解析冲突

图像 SQL 备注
线索中的图像之前
None (row was inserted on the source).
不适用
在线索中图像后
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=100 balance=100 comment=NULL last_mod_time='9/1/10 3:00'

last_mod_time='9/1/10 3:00 是分辨率列的后像。由于有后置图像,因此将用于确定分辨率。

目标数据库映像
name='Mary' phone='111111' address='Ralston' salary=200 balance=500 comment='aaa' last_mod_time='9/1/10 1:00'
last_mod_time='9/1/10 1:00 是目标中分辨率列的当前图像,用于比较线索中的分辨率列值。
检测冲突的复制应用初始 INSERT

SQL 绑定的变量:

1)'Mary' 2)'1234567890' 3)'Oracle Pkwy' 4)100 5)100 6)NULL 7)'9/1/10 3:00'
此 SQL 返回“Mary”上的唯一性冲突。
Replicat 应用 UPDATE 以解决冲突

SQL 绑定的变量:

1)'1234567890' 2)'Oracle Pkwy' 3)100 4)100 5)NULL 6)'9/1/10 3:00' 7)'Mary' 8)'9/1/10 3:00'
由于为 INSERTROWEXISTS 指定了 USEMAX,因此 Replicat 会将插入转换为更新,并将线索记录中的 last_mod_time 值与数据库中的值进行比较。记录中的值更大,因此线索文件中列的后续图像将应用于目标。

UPDATEROWEXISTS 与 USEMAX 解析

对于此示例,USEMAX 分辨率以线索和数据库中记录的适用图像之前和之后进行说明。它显示如何解析行存在于源和目标中的更新,但某些或所有行值不同。

表 11 UPDATEROWEXISTS 与 USEMAX 解决方法冲突

图像 SQL 备注
线索中的图像之前
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=100 balance=100 comment=NULL last_mod_time='9/1/10 3:00'
last_mod_time='9/1/10 3:00 是分辨率列的前一个图像。
在线索中图像后
phone='222222' address='Holly' last_mod_time='9/1/10 5:00'
last_mod_time='9/1/10 5:00 是分辨率列的后像。由于有后置图像,因此将用于确定分辨率。
目标数据库映像
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=100 balance=600 comment='com' last_mod_time='9/1/10 6:00'
last_mod_time='9/1/10 6:00 是目标中分辨率列的当前图像,用于比较线索中的分辨率列值。
检测冲突的复制应用初始 UPDATE

SQL 绑定的变量:

1)'222222' 2)'Holly' 3)'9/1/10 5:00' 4)'Mary' 5)'1234567890' 6)'Oracle Pkwy' 7)100 8)100 9)NULL 10)'9/1/10 3:00'

此 SQL 返回一个未找到数据的错误,因为目标中 balance、comment 和 last_mod_time 的值不同。

所有列都用在 WHERE 子句中,因为 COMPARECOLS 语句设置为 ALL。

Replicat 应用 UPDATE 以解决冲突

SQL 绑定的变量:

1)'Mary' 2)'222222' 3)'Holly' 4)100 5)100 6)NULL 7)'9/1/10 5:00' 8)'Mary' 9)'9/1/10 5:00'
由于线索记录中 last_mod_time 的后值小于数据库中的当前值,因此将保留数据库值。Replicat 使用包含主键加上设置为小于 9/1/10 5:00 的 last_mod_time 值的 WHERE 子句应用该操作。没有符合此条件的行,因此该语句会失败并显示“data not found(未找到数据)”错误,但 Replicat 会忽略该错误,因为如果不满足条件,USEMAX 解析会失败。

通过覆盖解析实现更新权限

对于此示例,OVERWRITE 分辨率以线索和数据库中记录的适用图像之前和之后进行说明。它显示如何解决缺少目标行的情况。逻辑解析和使用的逻辑解析是将行覆盖到目标中,以便两个数据库再次同步。

表 12 UPDATEROWMISSING 与 OVERWRITE Resolution 的冲突

图像 SQL 备注
线索中的图像之前
name='Jane' phone='333' address='Oracle Pkwy' salary=200 balance=200 comment=NULL last_mod_time='9/1/10 7:00'
不适用
在线索中图像后
phone='4444' address='Holly' last_mod_time='9/1/10 8:00'
 
目标数据库映像
None (row for Jane is missing)
 
检测冲突的复制应用初始 UPDATE

SQL 绑定的变量:

1)'4444' 2)'Holly' 3)'9/1/10 8:00' 4)'Jane' 5)'333' 6)'Oracle Pkwy' 7)200 8)200 9)NULL 10)'9/1/10 7:00'
此 SQL 返回“no-data-found(未找到数据)”错误。所有列都用在 WHERE 子句中,因为 COMPARECOLS 语句设置为 ALL。
Replicat 应用 INSERT 以解决冲突

SQL 绑定的变量:

1)'Jane' 2)'4444' 3)'Holly' 4)200 5)200 6)NULL 7)'9/1/10 8:00'
更新将转换为插入,因为 OVERWRITE 是分辨率。使用列的后图像(如果可用);否则使用之前的图像。

具有覆盖分辨率的 DELETEROWEXIST

对于此示例,OVERWRITE 分辨率以线索和数据库中记录的适用图像之前和之后进行说明。它显示如何解决删除来源行但目标行存在的情况。在这种情况下,OVERWRITE 解析会将删除应用于目标。

表 13 DELETEROWEXISTS 与 OVERWRITE 解析冲突

图像 SQL 备注
线索中的图像之前
name='Mary' phone='222222' address='Holly' salary=100 balance=100 comment=NULL last_mod_time='9/1/10 5:00'
不适用
在线索中图像后
None
不适用
目标数据库映像
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=100 balance=600 comment=com last_mod_time='9/1/10 7:00'
该行存在于目标上,但是 phone、address、balance、comment 和 last_mod_time 列与线索中的前一图像不同。
检测冲突的复制应用初始 DELETE

SQL 绑定的变量:

1)'Mary' 2)'222222' 3)'Holly' 4)100 5)100d 6)NULL 7)'9/1/10 5:00'

所有列都用在 WHERE 子句中,因为 COMPARECOLS 语句设置为 ALL。

由于前值与当前值之间的差异,将出现“未找到数据”错误。

Replicat 应用 DELETE 以解决冲突

SQL 绑定的变量:

1)'Mary'
因为 OVERWRITE 是解析。仅使用主键应用 DELETE(以避免完整性错误)。

使用 DISCARD 解析删除权限

对于此示例,DISCARD 分辨率以线索和数据库中记录的适用图像之前和之后进行说明。它显示如何解决缺少目标行的情况。对于源上的删除,目标行不存在是可以接受的(无论如何都需要将其删除),因此解决方法是放弃线索中的 DELETE 操作。

表 14 DELETEROWMSING 与 DISCARD Resolution 冲突

图像 SQL 备注
线索中的图像之前
name='Jane' phone='4444' address='Holly' salary=200 balance=200 comment=NULL last_mod_time='9/1/10 8:00'
不适用
在线索中图像后
None
不适用
目标数据库映像
None (row missing)
不适用
检测冲突的复制应用初始 DELETE

SQL 绑定的变量:

1)'Jane' 2)'4444' 3)'Holly' 4)200 5)200 6)NULL 7)'9/1/10 8:00'
此 SQL 返回“no-data-found(未找到数据)”错误。所有列都用在 WHERE 子句中,因为 COMPARECOLS 语句设置为 ALL。
复制应用 SQL 以解决冲突
None
因为 DISCARD 指定为 DELETEROWMISSING 的解析,所以从线索中删除将转至放弃文件。

CDR 示例 2:带有 USEDELTA 和 USEMAX 的 UPDATEROWEXISTS

此示例解析 UPDATE 上存在目标行但非键列不同的条件,并根据受影响的列使用两种不同的解析类型来处理此条件。

本示例中使用的表

这些示例假定相同的 Oracle 数据库。

CREATE TABLE tgt(
    name varchar2(30) primary key,
    phone varchar2(10),
    address varchar2(100),
    salary number,
    balance number,
    comment varchar2(100),
    last_mod_time timestamp);

在源数据库上,将补充记录所有列:

ADD TRANDATA scott.src, COLS (name, phone, address, salary, balance, comment, last_mod_time);

MAP 语句

MAP fin.src, TARGET fin.tgt,
    COMPARECOLS
    (ON UPDATE KEYINCLUDING (address, phone, salary, last_mod_time),
    ON DELETE KEYINCLUDING (address, phone, salary, last_mod_time)),
    RESOLVECONFLICT (
    UPDATEROWEXISTS,
    (delta_res_method, USEDELTA, COLS (salary)),
    (DEFAULT, USEMAX (last_mod_time)));

MAP 语句的说明

对于 UPDATEROWEXISTS 冲突,如果目标行存在于 UPDATE 上但非键列不同,则根据该列使用两个不同的解析:

根据 COMPARECOLS,使用主键(name 列)加上 address、phone、salary 和 last_mod_time 列作为 UPDATE 和 DELETE 操作的冲突检测比较列。(不比较 balance 列和 comment 列。)

注:作为 USEMAX 的替代方法,您可以使用 USEMAXEQ 解析来应用 >= 条件。有关详细信息,请参阅 Oracle GoldenGate 的参数和函数参考。

错误处理

有关异常表的错误处理的示例,请参阅配置 Oracle GoldenGate 参数文件以处理错误。

表 15 使用 USEDELTA 和 USEMAX 的 UPDATEROWEXISTS

图像 SQL 备注
线索中的图像之前
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=100 balance=100 comment=NULL last_mod_time='9/1/10 3:00'

last_mod_time='9/1/10 3:00 是 USEMAX 分辨率的分辨率列的前图像。

salary=100 是 USEDELTA 分辨率的先前映像。

在线索中图像后
phone='222222' address='Holly' salary=200 comment='new' last_mod_time='9/1/10 5:00'
last_mod_time='9/1/10 5:00 是 USEMAX 的分辨率列的后像。由于有后置图像,因此将用于确定分辨率。
目标数据库映像
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=600 balance=600 comment='com' last_mod_time='9/1/10 4:00'

last_mod_time='9/1/10 4:00 是目标中分辨率列的当前图像,用于比较线索中的分辨率列值。

salary=600 是 USEDELTA 分辨率的目标列的当前图像。

检测冲突的复制应用初始 UPDATE

SQL 绑定的变量:

1)'222222' 2)'Holly' 3)200 4)'new' 5)'9/1/10 5:00' 6)'Mary' 7)'1234567890' 8)'Oracle Pkwy' 9)100 10)'9/1/10 3:00'
此 SQL 返回“无数据发现”错误,因为 salary 和 last_mod_time 的值不同。(comment 和 balance 的值也不同,但不会比较这些列。)
Replicat 应用 UPDATE 以使用 USEDELTA 解决 salary 的冲突。

SQL 绑定的变量:

1)200 2)100 3)'Mary'

在 USEDELTA 中,轨迹中 salary (200) 的后映像与轨迹中 salary (100) 的前映像之间的差值将添加到目标 (600) 中的当前值 salary。结果为 700。

600 + (200 - 100) = 700
Replicat 应用 UPDATE,以使用 USEMAX 解决默认列的冲突。

SQL 绑定的变量:

1)'222222' 2)'Holly' 3)'new' 4)'9/1/10 5:00' 5)'Mary' 6)'9/1/10 5:00'

根据 USEMAX,由于线索记录中 last_mod_time 的后值大于数据库中的当前值,因此将使用线索记录中的后值更新该行。

请注意,此处未设置 salary 列,因为使用 USEDELTA 解析中的 UPDATE 解析该列。

CDR 示例 3:带有 USEDELTA、USEMAX 和 IGNORE 的 UPDATEROWEXISTS

此示例解决 UPDATE 上存在目标行但非键列不同的冲突,并根据受影响的列使用三种不同的解析类型来处理此条件。

本示例中使用的表

这些示例假定相同的 Oracle 数据库。

CREATE TABLE tgt(
    name varchar2(30) primary key,
    phone varchar2(10),
    address varchar2(100),
    salary number,
    balance number,
    comment varchar2(100),
    last_mod_time timestamp);

在源数据库上,将补充记录所有列:

ADD TRANDATA scott.src, COLS (name, phone, address, salary, balance, comment, last_mod_time);

MAP 语句

MAP fin.src, TARGET fin.tgt,
    COMPARECOLS
    (ON UPDATE ALLEXCLUDING (comment)),
    RESOLVECONFLICT (
    UPDATEROWEXISTS,
    (delta_res_method, USEDELTA, COLS (salary, balance)),
    (max_res_method, USEMAX (last_mod_time), COLS (address, last_mod_time)),
    (DEFAULT, IGNORE));

MAP 语句的说明

错误处理

有关异常表的错误处理的示例,请参阅配置 Oracle GoldenGate 参数文件以处理错误。

表 16 使用 USEDELTA、USEMAX 和 IGNORE 的 UPDATEROWEXISTS

图像 SQL 备注
线索中的图像之前
name='Mary' phone='1234567890' address='Oracle Pkwy' salary=100 balance=100 comment=NULL last_mod_time='9/1/10 3:00

last_mod_time='9/1/10 3:00 是 USEMAX 分辨率的分辨率列的前图像。

salary=100 和 balance=100 是 USEDELTA 分辨率的先前映像。

在线索中图像后
phone='222222' address='Holly' salary=200 comment='new' last_mod_time='9/1/10 5:00'

last_mod_time='9/1/10 5:00 是 USEMAX 的分辨率列的后像。由于有后置图像,因此将用于确定分辨率。

salary=200 是唯一可用于 USEDELTA 解析的映像。对于 balance,计算将使用之前的图像。

目标数据库映像
name='Mary' phone='1234567890' address='Ralston' salary=600 balance=600 comment='com' last_mod_time='9/1/10 4:00'

last_mod_time='9/1/10 4:00 是目标中分辨率列的当前图像,将线索中的分辨率列值与 USEMAX 进行比较。

salary=600 和 balance=600 是 USEDELTA 的目标列的当前映像。

检测冲突的复制应用初始 UPDATE

SQL 绑定的变量:

1)'222222' 2)'Holly' 3)200 4)'new' 5)'9/1/10 5:00' 6)'Mary' 7)'1234567890' 8)'Oracle Pkwy' 9)100 10)100 11)'9/1/10 3:00'
此 SQL 返回一个未找到数据的错误,因为 address、salary、balance 和 last_mod_time 列的值不同。
Replicat 应用 UPDATE 以使用 USEDELTA 解决 salary 的冲突。

SQL 绑定的变量:

1)200 2)100 3)'Mary'
对于 salary,差异为 100,但是 balance 的值没有更改,因此在更新 SQL 中不需要。根据 USEDELTA,轨迹中 salary 的后 (200) 图像和前 (100) 图像之间的差值(差值)将添加到目标 (600) 中的当前值 salary。结果为 700。
Replicat 应用 UPDATE 以解决 USEMAX 的冲突。

SQL 绑定的变量:

1)'Holly' 2)'9/1/10 5:00' 3)'Mary' 4)'9/1/10 5:00'

由于线索记录中 last_mod_time 的后值大于数据库中的当前值,因此该列加上 address 列将更新为线索记录中的后值。

请注意,此处未设置 salary 列,因为使用 USEDELTA 解析中的 UPDATE 解析该列。

Replicat 对 IGNORE 应用了 UPDATE。

SQL 绑定的变量:

1)'222222' 2)'new' 3)'Mary'
为 DEFAULT 列组(phone 和 comment)指定了 IGNORE,因此不应用解析 SQL。

配置 Oracle GoldenGate 参数文件以进行错误处理

手动 CDR 应与错误处理结合使用,以捕获已解决的错误和 CDR 无法解决的错误。

  1. 在以下其他错误处理参数之前执行冲突解决:HANDLECOLLSIONS、INSERTMISSINGUPDATES 和 REPERROR。使用 REPERROR 参数分配规则以处理无法由 CDR 解决的错误,或者分配不希望通过 CDR 处理的错误。可能适合让 REPERROR 处理一些错误,而 CDR 处理其他错误;但是,如果将 REPERROR 和 CDR 配置为处理相同的冲突,则 CDR 优先。INSERTMISSINGUPDATES 和 HANDLECOLLISIONS 参数还可用于处理 CDR 未处理的一些错误。有关这些参数的详细信息,请参阅Oracle GoldenGate 的参数和函数参考。

  2. (可选)创建例外情况表。当异常表与异常 MAP 语句一起使用时,Replicat 会将生成冲突(已解决与否)的每个操作发送到异常 MAP 语句,以映射到异常表。如果 Replicat 要处理 UPDATE 和 DELETE 冲突,请省略此表中的主键;否则可能会出现完整性约束条件错误。

    至少,异常表应包含与目标表相同的列。这些行将包含复制应用于目标的每个行映像(或尝试应用)。

    此外,还可以定义其他列来捕获有助于将数据置于事务处理上下文中的其他信息。Oracle GoldenGate 提供了通过异常 MAP 语句捕获此信息的工具。此类列可以是(但不限于)以下列:

    • 线索记录的以前图像。这是名称为 col1 _before、col2 _before 等的目标列的一组重复项。

    • 目标列的当前值。这也是名称为 col1 _current、col2 _current 等的目标列的一组重复项。

    • 目标表的名称

    • 冲突的时间戳

    • 操作类型

    • 数据库错误号

    • (可选)数据库错误消息

    • 是否已解决冲突

  3. 创建异常 MAP 语句以将异常数据映射到异常表。例外 MAP 语句包含:

    • (必需)INSERTALLRECORDS 选项。此参数将所有映射的操作转换为 INSERT,以便将所有列值映射至异常表。

    • (必需)EXCEPTIONSONLY 选项。此参数会导致 Replicat 映射生成错误的操作,但不会映射那些成功的操作。

    • (可选)COLMAP 子句。如果异常错误表中的列的名称和定义与源表中的列相同,并且异常错误表仅包含这些列,则不需要 COLMAP。但是,如果任何名称或定义不同,或者如果异常表中存在要用其他数据填充的额外列,请使用 COLMAP 子句映射所有列。

用于将附加数据映射到异常表的工具

以下是一些工具,您可以在 COLMAP 子句中使用这些工具来填充额外的列:

有关如何在例外 MAP 语句的 COLMAP 子句中组合这些功能以填充详细的例外表,请参阅例外表中的示例例外映射和附加列。

有关这些示例中所示的参数和列转换函数的使用和语法,请参阅Oracle GoldenGate 的参数和函数参考。

仅包含源列和目标列的示例例外映射

下面是一个示例参数文件,其中显示了开始的 CDR 示例中使用的源表和目标表的错误处理和简单异常映射。此示例映射源列和目标列,但不映射额外的列。出于以下原因,在此示例中的例外 MAP 语句中不需要 COLMAP 子句:

    -- REPERROR error handling: DEFAULT represents all error types. DISCARD

    -- writes operations that could not be processed to a discard file.
REPERROR (DEFAULT, DISCARD)

    -- Specifies a discard file.
DISCARDFILE /users/ogg/discards/discards.dsc, PURGE

    -- The regular MAP statement with the CDR parameters
MAP fin.src, TARGET fin.tgt, &
COMPARECOLS (ON UPDATE ALL, ON DELETE ALL), &
RESOLVECONFLICT (UPDATEROWEXISTS, (DEFAULT, USEMAX (last_mod_time)), &
RESOLVECONFLICT (INSERTROWEXISTS, (DEFAULT, USEMAX (last_mod_time)), &
RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, OVERWRITE)), &
RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)), &
RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD)), &
);

    -- Starts the exceptions MAP statement by mapping the source table to the

    -- exceptions table.
MAP fin.src, TARGET fin.exception, &

    -- directs Replicat only to map operations that caused the error specified

    -- in REPERROR.
EXCEPTIONSONLY, &

    -- directs Replicat to convert all the exceptions to inserts into the

    -- exceptions table. This is why there cannot be a primary key constraint

    -- on the exceptions table.
INSERTALLRECORDS
;

例外表中包含附加列的例外映射示例

下面是一个示例参数文件,其中显示了开始的 CDR 示例中使用的源表和目标表的错误处理和复杂异常映射。在此示例中,异常表具有与源表相同的行,但是它还具有用于捕获上下文数据的附加列。

注:此示例有意省略复制参数文件中需要的其他参数,例如进程名称和登录身份证明,以及给定数据库类型可能需要的任何可选参数。使用换行符将参数语句拆分为多行时,在每行的末尾使用“和”号 (&)。

    -- REPERROR error handling: DEFAULT represents all error types. DISCARD
    -- writes operations that could not be processed to a discard file.
REPERROR (DEFAULT, DISCARD)
    -- Specifies the discard file.
DISCARDFILE /users/ogg/discards/discards.dsc, PURGE
    -- The regular MAP statement with the CDR parameters
MAP fin.src, TARGET fin.tgt, &
COMPARECOLS (ON UPDATE ALL, ON DELETE ALL), &
RESOLVECONFLICT (UPDATEROWEXISTS, (DEFAULT, USEMAX (last_mod_time))), &
RESOLVECONFLICT (INSERTROWEXISTS, (DEFAULT, USEMAX (last_mod_time)), &
RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, OVERWRITE)), &
RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)), &
RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD))
);
    -- Starts the exceptions MAP statement by mapping the source table to the -- exceptions table.
MAP fin.src, TARGET fin.exception, &
    -- directs Replicat only to map operations that caused the error specified
    -- in REPERROR.
EXCEPTIONSONLY, &
    -- directs Replicat to convert all the exceptions to inserts into the
    -- exceptions table. This is why there cannot be a primary key constraint
    -- on the exceptions table.
INSERTALLRECORDS &
    -- SQLEXEC query to select the values from the target record before the
    -- Replicat statement is applied. These are mapped to the *_target
    -- columns later.
SQLEXEC (id qry, query 'select name, phone, address, salary, balance, & comment, last_mod_time from fin.tgt where name = :p1', PARAMS(p1 = name )), &
    -- Start of the column mapping, specifies use default column definitions.
COLMAP ( &
    -- USEDEFAULTS maps the source columns to the target exceptions columns
    -- that receive the after image that Replicat applied or tried to apply.
    -- In this case, USEDEFAULTS can be used because the names and definitions
    -- of the source and target exceptions columns are identical; otherwise
    -- the columns must be mapped explicitly in the COLMAP clause.
USEDEFAULTS, &
    -- captures the timestamp when the resolution was performed.
res_date = @DATENOW (), &
    -- captures and maps the DML operation type.
optype = @GETENV ('LASTERR', 'OPTYPE'), &
    -- captures and maps the database error number that was returned.
dberrnum = @GETENV ('LASTERR', 'DBERRNUM'), &
    -- captures and maps the database error that was returned.
dberrmsge = @GETENV ('LASTERR', 'DBERRMSG'), &
    -- captures and maps the name of the target table
tabname = @GETENV ('GGHEADER', 'TABLENAME'), &
    -- If the names and definitions of the source columns and the target
    -- exceptions columns were not identical, the columns would need to
    -- be mapped in the COLMAP clause instead of using USEDEFAULTS, as
    -- follows:
       -- name_after = name, &
       -- phone_after = phone, &
       -- address_after = address, &
       -- salary_after = salary, &
       -- balance_after = balance, &
       -- comment_after = comment, &
       -- last_mod_time_after = last_mod_time &
    -- maps the before image of each column from the trail to a column in the
    -- exceptions table.
name_before = @BEFORE (name), &
phone_before = @BEFORE (phone), &
address_before = @BEFORE (address), &
salary_before = @BEFORE (salary), &
balance_before = @BEFORE (balance), &
comment_before = @BEFORE (comment), &
last_mod_time_before = @BEFORE (last_mod_time), &
    -- maps the results of the SQLEXEC query to rows in the exceptions table
    -- to show the current image of the row in the target.
name_current = qry.name, &
phone_current = qry.phone, &
address_current = qry.address, &
salary_current = qry.salary, &
balance_current = qry.balance, &
comment_current = qry.comment, &
last_mod_time_current = qry.last_mod_time)
;

一旦您确信例程在所有情况下都能按预期工作,就可以减少记录到异常表中的数据量,以减少解决例程的开销。