Stream 同步错误之解决方案 ORA-00001 ORA-26787 ORA-26786
stream是 oracle 11g 支持的数据同步技术, 虽然该技术已经不是什么新技术, 但目前国内采用该技术开发的软件不多见. stream 同步软件项目参与近一年, 近期软件上线实施, 效果不是很理想. 同步过程中会偶尔出现 ORA-00001, ORA-26786, ORA-26787 等常见错误. 经过几天的的研究, 开发了一个守护平台,采用 java 平台和存储过程相结合的方式自动处理以上错误. 我写的这些算法具有通用性, 不需要手工指定删除表的列,通过实践具有较好的效果. 相对于set_update_conflict_handler这个方法,简单易用. java 平台代码便不开源了, 其实核心的思想还是在存储过程中, 特分享给大家, 共同进步.
自定义 type
create or replace type myvarray_list as varray(300) of varchar2(50)
CREATE OR REPLACE PROCEDURE EXECUTE_TRANSACTION_1(applyname IN VARCHAR2,ltxnid IN VARCHAR2) IS
i NUMBER;
x NUMBER;
loopdog NUMBER;
txnid VARCHAR2(30);
source VARCHAR2(128);
msgno NUMBER;
msgcnt NUMBER;
errno NUMBER;
errmsg VARCHAR2(2000);
lcr ANYDATA;
rowlcr SYS.LCR$_ROW_RECORD;
typenm VARCHAR2(61);
res NUMBER;
command VARCHAR2(10);
old_values SYS.LCR$_ROW_LIST;
new_values SYS.LCR$_ROW_LIST;
v_code NUMBER;
v_errm VARCHAR2(1024);
object_owner VARCHAR2(30);
object_name VARCHAR2(40);
key_column myvarray_list;
remove_column myvarray_list;
remove_flag NUMBER;
remove_count NUMBER;
BEGIN
SELECT LOCAL_TRANSACTION_ID,
SOURCE_DATABASE,
MESSAGE_NUMBER,
MESSAGE_COUNT,
ERROR_NUMBER,
ERROR_MESSAGE
INTO txnid, source, msgno, msgcnt, errno, errmsg
FROM DBA_APPLY_ERROR
WHERE LOCAL_TRANSACTION_ID = ltxnid;
DBMS_OUTPUT.PUT_LINE(' --- Local Transaction ID: ' || txnid);
DBMS_OUTPUT.PUT_LINE(' --- Source Database: ' || source);
DBMS_OUTPUT.PUT_LINE(' ---Error in Message: '|| msgno);
DBMS_OUTPUT.PUT_LINE(' ---Error Number: '||errno);
DBMS_OUTPUT.PUT_LINE(' ---Message Text: '||errmsg);
i := msgno;
loopdog :=0;
WHILE i <= msgcnt LOOP
loopdog :=loopdog+1;
DBMS_OUTPUT.PUT_LINE('---message: ' || i);
lcr := DBMS_APPLY_ADM.GET_ERROR_MESSAGE(i, txnid); -- gets the LCR
typenm := lcr.GETTYPENAME();
DBMS_OUTPUT.PUT_LINE('type name: ' || typenm);
IF (typenm = 'SYS.LCR$_ROW_RECORD') THEN
res := lcr.GETOBJECT(rowlcr);
command := rowlcr.GET_COMMAND_TYPE();
DBMS_OUTPUT.PUT_LINE('command type name: ' || command);
IF command = 'INSERT' THEN
rowlcr.SET_COMMAND_TYPE('DELETE');
new_values := rowlcr.GET_VALUES('new');
-- Set the old values in the row LCR to the new values in the row LCR
rowlcr.SET_VALUES('old', new_values);
-- Set the old values in the row LCR to NULL
rowlcr.SET_VALUES('new', NULL);
old_values := rowlcr.GET_VALUES('old');
-- Apply the row LCR as an DELETE FROM the table
object_name :=rowlcr.GET_OBJECT_NAME();
object_owner :=rowlcr.GET_OBJECT_OWNER();
key_column := myvarray_list(); --init array.
i :=1;
FOR emm IN (select DISTINCT CO.COLUMN_NAME from
DBA_cons_columns CO, dba_constraints PK
where CO.constraint_name = PK.constraint_name
AND CO.OWNER = PK.OWNER
AND PK.constraint_type IN ('P','C','U')
and PK.table_name = object_name
AND PK.OWNER=object_owner) LOOP
DBMS_OUTPUT.PUT_LINE('key column ' || emm.COLUMN_NAME);
key_column.extend;
key_column(i) := emm.COLUMN_NAME;
i :=i+1;
END LOOP;
remove_column := myvarray_list(); --init array.
remove_count := 1;
FOR i in 1..old_values.count LOOP
IF old_values(i) IS NOT NULL THEN
--DBMS_OUTPUT.PUT_LINE('old(' || i || '): ' || old_values(i).column_name);
x :=1;
remove_flag :=1;
WHILE x <= key_column.count AND remove_flag=1 loop
--dbms_output.put_line('key_column('||x||')='||key_column(x));
IF old_values(i).column_name = key_column(x) THEN
remove_flag :=0;
END IF;
x :=x +1;
END loop;
IF remove_flag = 1 then
remove_column.extend;
remove_column(remove_count) := old_values(i).column_name;
remove_count :=remove_count+1;
END IF;
END IF;
END LOOP;
FOR x in 1..remove_column.count loop
dbms_output.put_line('remove_column('||x||')='||remove_column(x));
rowlcr.DELETE_COLUMN(remove_column(x),'old');
END loop;
rowlcr.EXECUTE(true);
END IF;
BEGIN
--dbms_apply_adm.execute_all_errors(applyname);
dbms_apply_adm.EXECUTE_ERROR(ltxnid);
return;
EXCEPTION when OTHERS then
SELECT MESSAGE_NUMBER INTO i FROM DBA_APPLY_ERROR WHERE LOCAL_TRANSACTION_ID = ltxnid;
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 1024);
DBMS_OUTPUT.PUT_LINE('Error message: ' || v_errm);
IF loopdog > msgcnt then
RAISE_APPLICATION_ERROR(-20002,'Insert or Delete error. please check your procedure.');
ELSIF v_code = -1 then
DBMS_OUTPUT.PUT_LINE('Error code(-1): ' || v_code);
--null;
ELSIF v_code = -26786 then
DBMS_OUTPUT.PUT_LINE('Error code(-26786): ' || v_code);
RAISE_APPLICATION_ERROR(-20786,v_errm);
ELSIF v_code = -26787 then
DBMS_OUTPUT.PUT_LINE('Error code(-26787): ' || v_code);
RAISE_APPLICATION_ERROR(-20787,v_errm);
ELSE
RAISE_APPLICATION_ERROR(-20000,v_errm);
END IF;
END;
END IF;
END LOOP; --loop END EXECUTE_TRANSACTION_1;
--需要这两个 权限
--grant select on dba_constraints to DWESBSTREAMUSER;
--granT select on DBA_cons_columns to DWESBSTREAMUSER;
ORA-00001 错误是目标端存在数据,但是存在冲突列, 这里储存储过程的思想是根据唯一列删除目标端的对应行, 并将LCR 是old 值插入到目标端.
-----------------------------------------------------------------------------------------------------------------------------------
CREATE OR REPLACE PROCEDURE EXECUTE_TRANSACTION_26786(applyname IN VARCHAR2,ltxnid IN VARCHAR2) IS
i NUMBER;
x NUMBER;
loopdog NUMBER;
txnid VARCHAR2(30);
source VARCHAR2(128);
msgno NUMBER;
msgcnt NUMBER;
errno NUMBER;
errmsg VARCHAR2(2000);
lcr ANYDATA;
rowlcr SYS.LCR$_ROW_RECORD;
typenm VARCHAR2(61);
res NUMBER;
command VARCHAR2(10);
old_values SYS.LCR$_ROW_LIST;
new_values SYS.LCR$_ROW_LIST;
v_code NUMBER;
v_errm VARCHAR2(1024);
object_owner VARCHAR2(30);
object_name VARCHAR2(40);
key_column myvarray_list;
remove_column myvarray_list;
remove_flag NUMBER;
remove_count NUMBER;
BEGIN
SELECT LOCAL_TRANSACTION_ID,
SOURCE_DATABASE,
MESSAGE_NUMBER,
MESSAGE_COUNT,
ERROR_NUMBER,
ERROR_MESSAGE
INTO txnid, source, msgno, msgcnt, errno, errmsg
FROM DBA_APPLY_ERROR
WHERE LOCAL_TRANSACTION_ID = ltxnid;
DBMS_OUTPUT.PUT_LINE('--- Local Transaction ID: ' || txnid);
DBMS_OUTPUT.PUT_LINE('--- Source Database: ' || source);
DBMS_OUTPUT.PUT_LINE('---Error in Message: '|| msgno);
DBMS_OUTPUT.PUT_LINE('---Error Number: '||errno);
DBMS_OUTPUT.PUT_LINE('---Message Text: '||errmsg);
i := msgno;
loopdog :=0;
WHILE i <= msgcnt LOOP
loopdog :=loopdog+1;
DBMS_OUTPUT.PUT_LINE('---message: ' || i);
lcr := DBMS_APPLY_ADM.GET_ERROR_MESSAGE(i, txnid); -- gets the LCR
typenm := lcr.GETTYPENAME();
DBMS_OUTPUT.PUT_LINE('type name: ' || typenm);
IF (typenm = 'SYS.LCR$_ROW_RECORD') THEN
res := lcr.GETOBJECT(rowlcr);
command := rowlcr.GET_COMMAND_TYPE();
DBMS_OUTPUT.PUT_LINE('command type name: ' || command);
IF command IN ('DELETE','UPDATE') THEN
rowlcr.SET_COMMAND_TYPE('DELETE');
old_values := rowlcr.GET_VALUES('old');
-- Set the new values in the row LCR to NULL
rowlcr.SET_VALUES('new', NULL);
-- Apply the row LCR as an DELETE FROM the table --
object_name :=rowlcr.GET_OBJECT_NAME();
object_owner :=rowlcr.GET_OBJECT_OWNER();
---------------------------------------------------------------------------------------
key_column := myvarray_list(); --init array.
i :=1;
FOR emm IN (select DISTINCT CO.COLUMN_NAME from
DBA_cons_columns CO, dba_constraints PK
where CO.constraint_name = PK.constraint_name
AND CO.OWNER = PK.OWNER
AND PK.constraint_type IN ('P','C','U')
and PK.table_name = object_name
AND PK.OWNER=object_owner) LOOP
DBMS_OUTPUT.PUT_LINE('key column ' || emm.COLUMN_NAME);
key_column.extend;
key_column(i) := emm.COLUMN_NAME;
i :=i+1;
END LOOP;
-----------------------------------------------------------------------------------
remove_column := myvarray_list(); --init array.
remove_count := 1;
FOR i in 1..old_values.count LOOP
IF old_values(i) IS NOT NULL THEN
--DBMS_OUTPUT.PUT_LINE('old(' || i || '): ' || old_values(i).column_name);
x :=1;
remove_flag :=1;
WHILE x <= key_column.count AND remove_flag=1 loop
--dbms_output.put_line('key_column('||x||')='||key_column(x));
IF old_values(i).column_name = key_column(x) THEN
remove_flag :=0;
END IF;
x :=x +1;
END loop;
IF remove_flag = 1 then
remove_column.extend;
remove_column(remove_count) := old_values(i).column_name;
remove_count :=remove_count+1;
END IF;
END IF;
END LOOP; -----------------------------------------------------------------------------
FOR x in 1..remove_column.count loop
dbms_output.put_line('remove_column('||x||')='||remove_column(x));
rowlcr.DELETE_COLUMN(remove_column(x),'old');
END loop;
rowlcr.EXECUTE(true);
DBMS_OUTPUT.PUT_LINE('DELETE target old new ');
--- INSERT NEW DATA--
rowlcr.SET_COMMAND_TYPE('INSERT');
rowlcr.SET_VALUES('new',old_values);
rowlcr.SET_VALUES('old',NULL);
rowlcr.EXECUTE(true);
DBMS_OUTPUT.PUT_LINE('insert source old new');
END IF;
BEGIN
--dbms_apply_adm.execute_all_errors(applyname);
dbms_apply_adm.EXECUTE_ERROR(ltxnid);
return;
EXCEPTION when OTHERS then
SELECT MESSAGE_NUMBER INTO i FROM DBA_APPLY_ERROR WHERE LOCAL_TRANSACTION_ID = ltxnid;
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 1024);
DBMS_OUTPUT.PUT_LINE('Error message: ' || v_errm);
IF loopdog > msgcnt then
RAISE_APPLICATION_ERROR(-20002,'Insert or Delete error. please check your procedure.');
ELSIF v_code = -26786 then
DBMS_OUTPUT.PUT_LINE('Error code(-26786): ' || v_code);
ELSIF v_code = -26787 then
DBMS_OUTPUT.PUT_LINE('Error code(-26787): ' || v_code);
RAISE_APPLICATION_ERROR(-20787,v_errm);
ELSIF v_code = -1 then
DBMS_OUTPUT.PUT_LINE('Error code(-1): ' || v_code);
RAISE_APPLICATION_ERROR(-20001,v_errm);
ELSE
RAISE_APPLICATION_ERROR(-20000,v_errm);
END IF;
END;
END IF;
END LOOP; END EXECUTE_TRANSACTION_26786;
ORA-26786 思想与 ORA-00001 思想类似, 不再赘述.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE OR REPLACE PROCEDURE EXECUTE_TRANSACTION_26787(applyname IN VARCHAR2,ltxnid IN VARCHAR2) IS
i NUMBER;
loopdog NUMBER;
txnid VARCHAR2(30);
source VARCHAR2(128);
msgno NUMBER;
msgcnt NUMBER;
errno NUMBER;
errmsg VARCHAR2(2000);
lcr ANYDATA;
rowlcr SYS.LCR$_ROW_RECORD;
typenm VARCHAR2(61);
res NUMBER;
command VARCHAR2(10);
old_values SYS.LCR$_ROW_LIST;
new_values SYS.LCR$_ROW_LIST;
v_code NUMBER;
v_errm VARCHAR2(1024);
BEGIN
SELECT LOCAL_TRANSACTION_ID,
SOURCE_DATABASE,
MESSAGE_NUMBER,
MESSAGE_COUNT,
ERROR_NUMBER,
ERROR_MESSAGE
INTO txnid, source, msgno, msgcnt, errno, errmsg
FROM DBA_APPLY_ERROR
WHERE LOCAL_TRANSACTION_ID = ltxnid;
DBMS_OUTPUT.PUT_LINE('--- Local Transaction ID: ' || txnid);
DBMS_OUTPUT.PUT_LINE('--- Source Database: ' || source);
DBMS_OUTPUT.PUT_LINE('---Error in Message: '|| msgno);
DBMS_OUTPUT.PUT_LINE('---Error Number: '||errno);
DBMS_OUTPUT.PUT_LINE('---Message Text: '||errmsg);
i := msgno;
loopdog :=0;
WHILE i <= msgcnt LOOP
loopdog :=loopdog+1;
DBMS_OUTPUT.PUT_LINE('--message: ' || i);
lcr := DBMS_APPLY_ADM.GET_ERROR_MESSAGE(i, txnid); -- gets the LCR
--print_lcr(lcr);
typenm := lcr.GETTYPENAME();
DBMS_OUTPUT.PUT_LINE('type name: ' || typenm);
IF (typenm = 'SYS.LCR$_ROW_RECORD') THEN
res := lcr.GETOBJECT(rowlcr);
command := rowlcr.GET_COMMAND_TYPE();
DBMS_OUTPUT.PUT_LINE('command type name: ' || command);
IF command = 'DELETE' THEN
-- Set the command_type in the row LCR to INSERT
rowlcr.SET_COMMAND_TYPE('INSERT');
old_values := rowlcr.GET_VALUES('old');
-- Set the old values in the row LCR to the new values in the row LCR
rowlcr.SET_VALUES('new', old_values);
-- Set the old values in the row LCR to NULL
rowlcr.SET_VALUES('old', NULL);
-- Apply the row LCR as an INSERT into the hr.emp_del table
rowlcr.EXECUTE(true);
ELSIF command = 'UPDATE' THEN
BEGIN
old_values := rowlcr.GET_VALUES('old');
new_values := rowlcr.GET_VALUES('new');
rowlcr.EXECUTE(true);
rowlcr.SET_VALUES('new', old_values);
rowlcr.SET_VALUES('old', new_values);
rowlcr.EXECUTE(true);
EXCEPTION when OTHERS then
rowlcr.SET_COMMAND_TYPE('INSERT');
rowlcr.SET_VALUES('new', old_values);
-- Set the old values in the row LCR to NULL
rowlcr.SET_VALUES('old', NULL);
rowlcr.EXECUTE(true);
END;
END IF;
BEGIN
--dbms_apply_adm.execute_all_errors(applyname);
dbms_apply_adm.execute_error(ltxnid);
return;
EXCEPTION when OTHERS then
SELECT MESSAGE_NUMBER INTO i FROM DBA_APPLY_ERROR WHERE LOCAL_TRANSACTION_ID = ltxnid;
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 1024);
DBMS_OUTPUT.PUT_LINE('Error message: ' || v_errm);
IF loopdog > msgcnt then
RAISE_APPLICATION_ERROR(-20002,'Insert or Delete error. please check your procedure.');
ELSIF v_code = -26787 then
DBMS_OUTPUT.PUT_LINE('Error code(-26787): ' || v_code);
--null;
ELSIF v_code = -26786 then
DBMS_OUTPUT.PUT_LINE('Error code(-26786): ' || v_code);
RAISE_APPLICATION_ERROR(-20786,v_errm);
ELSIF v_code = -1 then
DBMS_OUTPUT.PUT_LINE('Error code(-1): ' || v_code);
RAISE_APPLICATION_ERROR(-20001,v_errm);
ELSE
RAISE_APPLICATION_ERROR(-20001,v_errm);
END IF;
END;
END IF;
END LOOP; END EXECUTE_TRANSACTION_26787;
ORA-26787 处理方法相对简单, 因为数据不存在引起的, 只要把LCR 中old 字段插入即可.
参考 :
-- https://docs.oracle.com/cd/B28359_01/server.111/b28321/strms_apmon.htm
-- https://docs.oracle.com/cd/B10501_01/server.920/a96571/capappdemo.htm
-- https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/t_lcr.htm#i997627
Stream 同步错误之解决方案 ORA-00001 ORA-26787 ORA-26786的更多相关文章
- Oracle启动中,spfile.ora、init<SID>.ora、spfile<SID>.ora 这三个文件正确的先后顺序是什么?
Oracle启动中,spfile.ora.init<SID>.ora.spfile<SID>.ora 这三个文件正确的先后顺序是什么? 解答:启动数据库,使用startup命令 ...
- oracle--本地网络配置tnsnames.ora和监听器listener.ora
文件tnsnames.ora 是给orcl客户端使用 配置本地网络服务:(客户端) 第一种使用暴力方式直接操作: 修改:C:\app\Administrator\product\11.2.0\dbho ...
- Oracle的tnsnames.ora配置(PLSQL Developer)
首先打开tnsnames.ora的存放目录,一般为D:\app\Administrator\product\11.2.0\client_1\network\admin,就看安装具体位置了. 步骤阅读 ...
- listener.ora/sqlnet.ora/tnsnames.ora配置文件详解
oracle网络配置 三个配置文件 listener.ora.sqlnet.ora.tnsnames.ora ,都是放在$ORACLE_HOME/network/admin目录下. 英文说明: The ...
- Oracle的sqlnet.ora与password文件试验
先看有没有sqlnet.ora [oracle@localhost ~]$ cd $ORACLE_HOME[oracle@localhost dbhome_1]$ cd network[oracle@ ...
- 转载《Oracle的tnsnames.ora配置(PLSQL Developer)》
源地址:https://www.cnblogs.com/qq3245792286/p/6212617.html. 首先打开tnsnames.ora的存放目录,一般为D:\app\Administrat ...
- [转帖]sqlnet.ora常用参数
sqlnet.ora常用参数 注﹕在修改sqlnet.ora文件之后重新启动监听﹐修改才能生效﹗﹗﹗ oracle网络设置主要包括三个文件,sqlnet.ora\ lisnter.ora\ tnsna ...
- PLSQL连接ORACLE配置字符串简介 oracle网络配置 三个配置文件 listener.ora、sqlnet.ora、tnsnames.ora原理解释
PLSQL连接ORACLE配置字符串简介 oracle网络配置 三个配置文件 listener.ora.sqlnet.ora.tnsnames.ora原理解释 oracle网络配置三个配置文件 lis ...
- oracle安装完成后目录中不论有没有tnsnames.ora和listener.ora文件 PLSQL都能连上的问题解决方法
今天遇到这个问题了,发现listener.ora文件和tnsnames.ora文件在Net Work文件夹下没有,正常情况下安装完oracle或者是oracle Client是会有的,但是在Net M ...
随机推荐
- software_testing_work3_question1
package com.Phantom; import java.io.IOException; import java.util.Scanner; public class Work3_1 { /* ...
- react native 之 react-native-image-picke的详细使用图解
最近需要在react native项目中集成相机和相册的功能,于是在网上找了一个好用的第三方插件:react-native-image-picke. 该插件可以同时给iOS和Android两个平台下使 ...
- Html 之div+css布局之css基础
Css是什么 CSS即层叠样式表(Cascading StyleSheet). 在网页制作时采用层叠样式表技术,可以有效地对页面的布局.字体.颜色.背景和其它效果实现更加精确的控制. 只要对相应的代码 ...
- winform 自定义控件引用问题
最近做了一个仿combobox的控件,与combobox类似,多了文字筛选的功能,如何实现在这里不再赘述.由于comboboxEx中用到了另一个用户控件,当生成dll,引用到项目中去时,发现工具栏中不 ...
- RabbitMQ在window的搭建
RabbitMq window 搭建设置过程,网上有些说的不太明白,所以亲自操刀测试过程,参考了很多人的资料,多谢各位大神的宝贵资料第一步:装RabbitMq运行环境,类似一个虚拟机的东东 1.otp ...
- The Swift Programming Language 中文翻译版(个人翻新随时跟新)
The Swift Programming Language --lkvt 本人在2014年6月3日(北京时间)凌晨起来通过网络观看2014年WWDC 苹果公司的发布会有iOS8以及OS X 10.1 ...
- 学习RaphaelJS矢量图形包--Learning Raphael JS Vector Graphics中文翻译(一)
(原文地址:http://www.cnblogs.com/idealer3d/p/LearningRaphaelJSVectorGraphics.html) 前面3篇博文里面,我们讲解了一本叫做< ...
- css中font-size的单位总结:px、em、pt
px:基于像素的单位.像素是一种有用的单位,因为在任何媒体上都可以保证一个像素的差别确实是可见的.em :一般用来测量长度的通用单位(例如元素周转的页边空白和填充),当用于指定字体大小时,em单位是指 ...
- 【Cocos2d-x 3.x】内存管理机制与源码分析
侯捷先生说过这么一句话 : 源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...
- CE STEPLDR
作用:初始化CPU.内存.Flash,复制EBoot到内存并跳入EBoot中运行. 原理:S3C2416有 8-KB 的steppingstone(暂时翻译为垫脚石),在Nand启动模式下可把Nand ...