对于表的主键列进行更新时,如果更新语句为set x=x+n或者更新过程中涉及到主键值的偏移,这种事务在源端可以正常执行,因为更新操作是在同一个语句中完成的。而对于HVR目标端来说,可能会把源端的一个更新语句转换为多个更新语句如:
目标端在执行上面的语句时会触发主键约束而报错:
ORA-00001: unique constraint (WZTEST.SYS_C005212) violated
在Oracle 11.2.0.2之前可以使用HANDLETPKUPDATE参数来解决,报错问题。
不过这个参数的使用有一个限制条件,就是对应表的主键要修改成deferrable状态。
alter table WZTEST.TB
drop constraint SYS_C005213 cascade;
alter table WZTEST.TB
add primary key (ID)
deferrable;
这只是一种临时的解决办法,当主键表太多时就不太适用了。
参数HANDLETPKUPDATE的使用方式
replicat reppart
setenv ( NLS_LANG = "AMERICAN_AMERICA.ZHS16GBK" )
assumetargetdefs
userid goldengate, password oracleoracle
DBOPTIONS DEFERREFCONST, SUPPRESSTRIGGERS
gettruncates
ALLOWNOOPUPDATES
ddl include mapped
discardfile ./dirrpt/reppart.dsc, purge, megabytes 5000
MAP WZTEST.*, target WZTEST.*, HANDLETPKUPDATE;
通过10046跟踪可以得到goldengate应用进程在执行对pk的update前后会执行下面的两个语句。执行更新操作前它会把constraint设置为deferred状态,更新完成之后,再设置成immediate状态。
alter session set constraint = deferred
UPDATE /*+ RESTRICT_ALL_REF_CONS */ "WZTEST"."TB" SET "ID" = :a1 WHERE "ID" = :b0 AND rowid <> :rid
alter session set constraint = immediate
Oracle11.2.0.3中的存储过程DBMS_XSTREAM_GG.ENABLE_TDUP_WORKSPACE可以解决这个问题,使用这个存储过程不再需要对表的主键状态进行修改,也不需要在Goldengate的参数文件中使用handletpkupdate参数。
这个存储过程是数据库自带的,即使没有部署Goldengate 数据库中也有这个存储过程。
通过10046可以看到goldengate的应用进程中显示了调用了dbms_xstream_gg.enable_tdup_workspace和dbms_xstream_gg.disable_tdup_workspace两个存储过程。
begin dbms_xstream_gg.enable_tdup_workspace; end;
update …
begin dbms_xstream_gg.disable_tdup_workspace; end;
这两个存储过程在数据库中是加密的,具体的实现,不得而知。
参考文档:
GoldenGate REPLICAT abend ORA-00001: unique constraint violated on transient PKUpdate in 11.2.0.4 (Doc ID 1928263.1)
Usage of Handletpkupdate requires specific defer settings on table (Doc ID 1303231.1)
Oracle® GoldenGate Windows and UNIX Reference Guide 11g Release 2 Patch Set 1 (11.2.1.0.1)