3.繼續測試:
SQL> create table hz.t6 (id number primary key ,vname varchar2(20),vaddr varchar2(20),vqty number);
Table created
SQL> insert into hz.t6 values (1,'a1','guangzhou',100);
1 row inserted
SQL> insert into hz.t6 values (2,'b1','zhenzhou',300);
SQL> insert into hz.t6 values (3,'c1','zhenming',200);
SQL> commit;
Commit complete
SQL> select * from hz.t6;
ID VNAME VADDR VQTY
---------- -------------------- -------------------- ----------
1 a1 guangzhou 100
2 b1 zhenzhou 300
3 c1 zhenming 200
檢視目标庫,也是3條記錄:
SQL> select * from hz.t6;
目标庫做删除操作:
SQL> DELETE HZ.T6 WHERE ID=3;
1 row deleted
原庫也删除相同的序号3記錄,
SQL> delete hz.t6 where id=3;
目标庫的應用程序顯示abort.
SQL> select status from dba_apply;
STATUS
--------
ABORTED
應用程序的錯誤資訊,
SQL> select LOCAL_TRANSACTION_ID,ERROR_MESSAGE from dba_apply_error;
LOCAL_TRANSACTION_ID ERROR_MESSAGE
---------------------- ----------------------------------------------------------------------
1.16.629 ORA-26787: The row with key ("ID") = (3) does not exist in table HZ.T1
ORA-01403: no data found
沖突解決
-------------------
沖突有很多類型,stream提供更新操作沖突類型的handler,其他類型的handler需要自己定義:
自定義handler的方法:
You use the SET_DML_HANDLER procedure in the DBMS_APPLY_ADM package to designate one or more custom conflict handlers for a particular table
CREATE TABLE strmadmin.history_row_lcrs(
timestamp DATE,
source_database_name VARCHAR2(128),
command_type VARCHAR2(30),
object_owner VARCHAR2(32),
object_name VARCHAR2(32),
tag RAW(10),
transaction_id VARCHAR2(10),
scn NUMBER,
commit_scn NUMBER,
old_values SYS.LCR$_ROW_LIST,
new_values SYS.LCR$_ROW_LIST)
NESTED TABLE old_values STORE AS old_values_ntab
NESTED TABLE new_values STORE AS new_values_ntab;
SQL> CREATE TABLE event_log (id NUMBER, timestamp DATE, event VARCHAR2(2000));
SQL> create sequence seq_event increment by 1 start with 1 nomaxvalue nocache;
Sequence created
CREATE OR REPLACE PROCEDURE hz_t5_handler(in_any IN SYS.ANYDATA) IS
lcr SYS.LCR$_ROW_RECORD;
rc PLS_INTEGER;
object_owner VARCHAR2(30);
object_name VARCHAR2(40);
dmlcommand VARCHAR2(10);
v_name varchar2(20) := ' ';
v_old_id_anydata SYS.ANYDATA;
v_old_id number;
v_dummy PLS_INTEGER;
v_sqlcode varchar2(32);
v_sqlerrm varchar2(255);
--v_typecode PLS_INTEGER;
--v_type SYS.ANYTYPE;
non_null_anytype_for_NUMBER exception;
unknown_typename exception;
v_cnt number;
BEGIN
-- Access the LCR
rc := in_any.GETOBJECT(lcr);
object_owner := lcr.GET_OBJECT_OWNER();
object_name := lcr.GET_OBJECT_NAME();
dmlcommand := lcr.GET_COMMAND_TYPE();
if dmlcommand in ('INSERT') then
v_old_id_anydata := lcr.get_value('NEW', 'NO', 'Y');
elsif dmlcommand in ('DELETE') then
v_old_id_anydata := lcr.get_value('OLD', 'NO');
else
null;
end if;
-- Insert information about the LCR into the history_row_lcrs table
INSERT INTO strmadmin.history_row_lcrs
VALUES
(SYSDATE,
lcr.GET_SOURCE_DATABASE_NAME(),
lcr.GET_COMMAND_TYPE(),
lcr.GET_OBJECT_OWNER(),
lcr.GET_OBJECT_NAME(),
lcr.GET_TAG(),
lcr.GET_TRANSACTION_ID(),
lcr.GET_SCN(),
lcr.GET_COMMIT_SCN,
lcr.GET_VALUES('old'),
lcr.GET_VALUES('new', 'n'));
commit;
v_dummy := v_old_id_anydata.GetNUMBER(v_old_id /* OUT */);
DBMS_OUTPUT.PUT_LINE(TO_CHAR(rc) || To_Char(v_dummy)); --臨時加的字段
if v_cnt = 1 then
IF object_owner = 'HZ' and object_name = 'T6' and dmlcommand IN ('INSERT' /*, 'DELETE', 'UPDATE'*/
) THEN
-- Add Columns
lcr.add_column('NEW', 'NAME', sys.anydata.convertvarchar2(v_name));
ELSE
lcr.add_column('OLD', 'NAME', sys.anydata.convertvarchar2(v_name));
END IF;
LCR.EXECUTE(TRUE);
elsif v_cnt = 0 then
lcr.add_column('NEW', 'NAME', sys.anydata.convertvarchar2(' '));
lcr.add_column('OLD', 'NAME', sys.anydata.convertvarchar2(' '));
insert into event_log
(id, timestamp, event)
values
(seq_event.nextval,
sysdate,
'succeed! v_id=' || v_old_id || 'cnt=' || v_cnt || ',dmlcommand=' ||
dmlcommand || ',v_name=' || v_name);
exception
when others then
rollback;
v_sqlcode := sqlcode;
v_sqlerrm := sqlerrm;
insert into event_log
(id, timestamp, event)
values
(seq_event.nextval,
sysdate,
v_sqlcode || '|' || v_sqlerrm || ',v_old_id=' || v_old_id || ',cnt=' ||
--v_cnt || ',v_name=' || v_name || ',dmlcommand=' || dmlcommand);
v_cnt || ',v_name=' || v_name || ',dmlcommand=' || dmlcommand || TO_CHAR(rc)|| To_Char(v_dummy) );
commit;
END;
SQL> BEGIN
2 DBMS_APPLY_ADM.SET_DML_HANDLER(
3 object_name => 'hz.t6',
4 object_type => 'TABLE',
5 operation_name => 'DELETE',
6 error_handler => false,
7 user_procedure => 'strmadmin.hz_t5_handler',
8 apply_database_link => NULL,
9 apply_name => NULL);
10 END;
11 /
PL/SQL procedure successfully completed
5 operation_name => 'INSERT',
删除之前的應用程序錯誤号資訊,重新時應用日志應用。
SQL> exec dbms_apply_adm.execute_all_errors('APPLY_STANDY');
SQL> exec dbms_apply_adm.start_apply('APPLY_STANDY');
原庫重新插入id=3的記錄:
目标庫的應用程序還是正常的.
SQL> select APPLY_NAME,status from dba_apply;
APPLY_NAME STATUS
------------------------------ --------
APPLY_STANDY ENABLED
SQL> select * from event_log;
ID TIMESTAMP EVENT
---------- ----------- -----------------------------------------------------------
2 2010-10-15 -30625|ORA-30625: method dispatch on NULL SELF argument is disallowed,v_old_id=,cnt=,v_name= ,dmlcommand=DELETE
目标庫插入需要6的記錄:
SQL> insert into hz.t6 values (6,'e1','haikou',600);
原庫也插入目标為6的序号:
SQL> insert into hz.t6 values (6,'e1','haikou',600);
---------- ----------- --------------------------------------------------------------------------
3 2010-10-15 -30625|ORA-30625: method dispatch on NULL SELF argument is disallowed,v_old_id=,cnt=,v_name= ,dmlcommand=INSERT
至此t6表的插入,删除操作 都已經正常進行,不會因為沖突而中斷應用程序的應用了。
本文轉自 gjm008 51CTO部落格,原文連結:http://blog.51cto.com/gaoshan/406547,如需轉載請自行聯系原作者