2016-08-26 2 views
2

하나의 데이터베이스에서 AQ 전파에 대한 작업을하고 있습니다. 그러나 전파를 예약하고 LOCAL AQ 테이블에 첫 번째 메시지를 대기열에 추가하면 DBA_QUEUE_SCHEDULES.LAST_ERROR_MSG에서 오류가 발생했습니다. "ORA-25215 : user_data 유형과 대기열 유형이 일치하지 않습니다." , 내가 같은 스크립트를 사용하여 만든 이름 만 변경 한,Oracle AQ 전파, ORA-25215 : user_data 유형 및 대기열 유형이 일치하지 않습니다.

create or replace type LOCAL_OBJ_MSG as object(
    test varchar2(4000)) 
/

및 AQ 테이블 모두는 동일하다 : AQ 테이블에 사용 된 두 개체 유형 테스트 목적으로, 동일 내가이 일을 사용하고 있습니다 하나의 로컬 다른 원격. LOCAL AQ 테이블은 LOCAL 데이터베이스에 있으며, REMOTE 테이블은 SCHEMA_NAME.REMOTE 데이터베이스에 있습니다.

begin 
    -- Add the remote subscriber. 
    dbms_aqadm.add_subscriber(queue_name  => 'LOCAL_oTEST', 
          subscriber  => sys.aq$_agent(name  => 'LOCAL_oTEST_subscriber', 
                  address => '[email protected]_LINK_NAME', 
                  protocol => 0), 
          queue_to_queue => true); 
    -- Start the propagation of messages. 
    dbms_aqadm.schedule_propagation(queue_name  => 'LOCAL_oTEST', 
            latency   => 0, 
            destination  => 'DB_LINK_NAME', 
            destination_queue => 'SCHEMA_NAME.REMOTE_oTEST'); 
end; 
/

: 스크립트 가입자, 디큐 절차 등 :

LOCAL DB를 생성하는 데 사용 여기

declare 
    QUEUE_NOT_FOUND exception; 
    PRAGMA EXCEPTION_INIT(QUEUE_NOT_FOUND, -24010); 
begin 
    dbms_aqadm.stop_queue(
    queue_name => 'REMOTE_iTEST'); 
exception 
    when QUEUE_NOT_FOUND then 
    null; 
    when others then 
    raise; 
end; 
/

declare 
    QUEUE_NOT_FOUND exception; 
    PRAGMA EXCEPTION_INIT(QUEUE_NOT_FOUND, -24010); 
begin 
    dbms_aqadm.drop_queue('REMOTE_iTEST'); 
exception 
    when QUEUE_NOT_FOUND then 
    null; 
    when others then 
    raise; 
end; 
/

declare 
    QUEUE_NOT_FOUND exception; 
    PRAGMA EXCEPTION_INIT(QUEUE_NOT_FOUND, -24002); 
begin 
    dbms_aqadm.drop_queue_table('REMOTE_iTEST', force => true); 
exception 
    when QUEUE_NOT_FOUND then 
    null; 
    when others then 
    raise; 
end; 
/

declare 
    QUEUE_NOT_FOUND exception; 
    PRAGMA EXCEPTION_INIT(QUEUE_NOT_FOUND, -24010); 
begin 
    dbms_aqadm.stop_queue(
    queue_name => 'REMOTE_oTEST'); 
exception 
    when QUEUE_NOT_FOUND then 
    null; 
    when others then 
    raise; 
end; 
/

declare 
    QUEUE_NOT_FOUND exception; 
    PRAGMA EXCEPTION_INIT(QUEUE_NOT_FOUND, -24010); 
begin 
    dbms_aqadm.drop_queue('REMOTE_oTEST'); 
exception 
    when QUEUE_NOT_FOUND then 
    null; 
    when others then 
    raise; 
end; 
/

declare 
    QUEUE_NOT_FOUND exception; 
    PRAGMA EXCEPTION_INIT(QUEUE_NOT_FOUND, -24002); 
begin 
    dbms_aqadm.drop_queue_table('REMOTE_oTEST', force => true); 
exception 
    when QUEUE_NOT_FOUND then 
    null; 
    when others then 
    raise; 
end; 
/

declare 
    l_exist number; 
    cursor c_index is 
    select 1 from user_objects u where u.OBJECT_NAME = upper('LOCAL_OBJ_MSG') and u.OBJECT_TYPE = 'TYPE'; 
begin 
    open c_index; 
    fetch c_index into l_exist; 
    close c_index; 

    if l_exist = 1 then 
    execute immediate 'drop type LOCAL_OBJ_MSG'; 
    end if; 
end; 
/

create or replace type LOCAL_OBJ_MSG as object(
    test varchar2(4000))  
/

begin 
    dbms_aqadm.create_queue_table (
    queue_table => 'REMOTE_iTEST', 
    queue_payload_type => 'LOCAL_OBJ_MSG', 
    storage_clause => 'pctfree 5 pctused 90 tablespace SEPA_INTEG_AQ', 
    message_grouping => DBMS_AQADM.NONE, 
    sort_list => 'ENQ_TIME', 
    multiple_consumers => true, 
    comment => 'Incoming TEST message table.'); 
end; 
/

begin 
    dbms_aqadm.create_queue (
    queue_table => 'REMOTE_iTEST', 
    queue_name  => 'REMOTE_iTEST', 
    queue_type => sys.dbms_aqadm.normal_queue, 
    retention_time => sys.dbms_aqadm.INFINITE, 
    comment => 'Incoming TEST messages.', 
    max_retries => 5); 
end; 
/

begin 
    dbms_aqadm.start_queue(
    queue_name => 'REMOTE_iTEST', 
    dequeue  => true, 
    enqueue  => true); 
end; 
/
begin 
    dbms_aqadm.create_queue_table (
    queue_table => 'REMOTE_oTEST', 
    queue_payload_type => 'LOCAL_OBJ_MSG', 
    storage_clause => 'pctfree 5 pctused 90 tablespace SEPA_INTEG_AQ', 
    message_grouping => DBMS_AQADM.NONE, 
    sort_list => 'ENQ_TIME', 
    multiple_consumers => true, 
    comment => 'Outgoing TEST message table.'); 
end; 
/

begin 
    dbms_aqadm.create_queue (
    queue_table => 'REMOTE_oTEST', 
    queue_name  => 'REMOTE_oTEST', 
    queue_type => sys.dbms_aqadm.normal_queue, 
    retention_time => sys.dbms_aqadm.INFINITE, 
    comment => 'Outgoing TEST messages.', 
    max_retries => 5); 
end; 
/

begin 
    dbms_aqadm.start_queue(
    queue_name => 'REMOTE_oTEST', 
    dequeue  => TRUE, 
    enqueue  => TRUE); 
end; 
/

을 그리고 다음은

내가 AQ 테이블을 만드는 데 사용했습니다 스크립트입니다 원격 데이터베이스 :

-- Create a table to store the messages received. 
create table sepa_omsg_aq_demo 
    (received timestamp default systimestamp, 
    message LOCAL_OBJ_MSG); 

-- Create a callback procedure that dequeues the received message and saves it 
create or replace 
procedure REMOTE_CALLBACK_TEST 
    (
    context raw, 
    reginfo sys.aq$_reg_info, 
    descr sys.aq$_descriptor, 
    payload raw, 
    payloadl number 
) 
as 
    r_dequeue_options dbms_aq.dequeue_options_t; 
    r_message_properties dbms_aq.message_properties_t; 
    v_message_handle raw(26); 
    o_payload LOCAL_OBJ_MSG; 
begin 
    r_dequeue_options.msgid   := descr.msg_id; 
    r_dequeue_options.consumer_name := descr.consumer_name; 
    dbms_aq.dequeue(queue_name => descr.queue_name, 
        dequeue_options => r_dequeue_options, 
        message_properties => r_message_properties, 
        payload => o_payload, 
        msgid => v_message_handle); 
    insert into sepa_omsg_aq_demo 
    (message) 
    values (o_payload); 
    commit; 
exception 
    when others then 
    rollback; 
end; 
/

-- Register the procedure for dequeuing the messages received. 
-- I'd like to point out that the subscriber is the one defined for the local database 
begin 
    dbms_aq.register (
    sys.aq$_reg_info_list(
     sys.aq$_reg_info('REMOTE_oTEST:LOCAL_oTEST_subscriber', 
         dbms_aq.namespace_aq, 
         'plsql://REMOTE_CALLBACK_TEST', 
         hextoraw('FF')) 
         ), 
     1); 
end; 
/

declare 
    enq_msgid raw(16); 
    eopt  dbms_aq.enqueue_options_t; 
    mprop  dbms_aq.message_properties_t; 

    message local_obj_msg; 
begin 
    message := local_obj_msg('a'); 
    dbms_aq.enqueue(queue_name   => 'LOCAL_oTEST', 
        enqueue_options => eopt, 
        message_properties => mprop, 
        payload   => message, 
        msgid    => enq_msgid); 
    commit; 
end; 
/

은 또한 SYS.AQ $ _MESSAGE_TYPES 테이블 (LOCAL DB), 생성 된 전파 확인 상태 = 'F'에서 점에 유의하고, :

Sript은 LOCAL AQ 테이블에 메시지를 대기열하기

declare 
    rc binary_integer; 
begin 
    dbms_aqadm.verify_queue_types(src_queue_name => 'local_otest', 
           dest_queue_name => 'schema_name.remote_otest', 
           rc    => rc, 
           destination  => 'db_link_name'); 
    dbms_output.put_line('Compatible: ' || rc); 
end; 
/

은 0을 반환합니다. 이는 테이블 유형이 호환되지 않음을 의미합니다. 내가 로컬 파견과 NLS_LENGTH_SEMANTICS의 원격 데이터베이스가 다르다면, 원격 파급이 불가능하다는 것을 발견했다. 그러나이 상황에서는 그렇지 않다. 나는 확인했다. 어떤 생각이 내가 뭘 잘못하고 있는지 또는 어떻게이 두 테이블간에 차이점을 발견하고이를 고칠 수 있습니까? 또는 그것은 아마도 일부 DB 매개 변수 값 사이의 차이 일 수 있습니까?

오라클 데이터베이스는 확인 11.2.0.3.0

답변

1

한 영역을 11g 릴리스 각 데이터베이스에 NLS_LENGHT_SEMANTICS 매개 변수 값입니다.

NLS_LENGTH_SEMANTICS

는 오히려 바이트의 관점에서 문자의 측면에서 열 데이터 형식의 길이를 지정할 수 있습니다.

귀하의 PL/SQL 유형 생성 스크립트는 암시 적으로 VARCHAR2 길이 내에서 BYTE 또는 CHAR 변환을 사용하지 않습니다. 이로 인해 유형 생성이 NLS_LENGTH_SEMANTICS에 설정된 값을 상속받습니다.

두 데이터베이스의 NLS_LENGTH_SEMANTICS 값을 확인하십시오. 값이 다른 경우 (BYTE 대 CHAR) 문제의 원인이 될 수 있습니다. VARCHAR2 i에서 BYTE 또는 CHAR을 명시 적으로 사용하여 데이터베이스 중 하나에서 유형과 대기열을 재 빌드 할 수 있습니다.전자

create or replace type LOCAL_OBJ_MSG as object(
    test varchar2(4000 CHAR)) 
/

하거나 일치하는지 확인하기 위해 NLS_LENGTH_SEMANTICS에게 데이터베이스 중 하나에을 변경합니다. 변경 후 데이터베이스를 다시 컴파일해야합니다. NLS_LENGTH_SEMANTICS

+0

답해 주셔서 감사합니다. 그러나 두 데이터베이스 모두에서 NLS_LENGTH_SEMANTICS는 CHAR로 설정됩니다. –

+0

2 개의 Oracle 11.2.0.3.0에서 제공 한 스크립트를 성공적으로 실행했습니다. 메시지를 Enqueing하면 문제없이 잘 작동하며 메시지는 원격 대기열로 전달됩니다. 나는 그것이 명백하게 들릴지도 모르지만 NLS 주제를 방문한다는 것을 알고 있습니다. 귀하의 dbs에 대해 이것이 동일하다는 것을 확인할 수 있습니까? 'select * from nls_database_parameters 여기서, parameter = 'NLS_LENGTH_SEMANTICS'; select * from nls_instance_parameters 여기서 매개 변수 = 'NLS_LENGTH_SEMANTICS'; select * from nls_session_parameters 여기서 parameter = 'NLS_LENGTH_SEMANTICS'; ' –

+0

예, 이들은 다릅니다. 리모컨에서 CHAR, CHAR, CHAR, LOCAL, BYTE, CHAR, CHAR가 있습니다. 이전에 v $ 매개 변수를 체크인했는데이 뷰에 대해서는 알지 못했습니다. 그래서 지금은 내 원격 객체를 다시 만들 필요가 ... varchar2 (4000 CHAR)) ...? –

0

나는 조금 늦게 게시하고 있지만 이에 대한 해결 방법이 있습니다. 다른 의미론을 가진 두 데이터베이스 간 전파에서 객체 유형을 페이로드로 사용할 수는 없지만 전파 할 수있는 xmltype에 해당 객체 유형을 전파 할 때 변환을 지정할 수 있습니다. 이를 위해서는 xmltype을 수신 할 원격 데이터베이스에 대기열 (queue)이 필요합니다. 그런 다음 스케줄러 작업을 할 수 있습니다. 스케줄러 작업은 주기적으로 대기열에서 메시지를 대기열에서 제외하고 원격 대상 대기열에 대기열에 추가합니다. dequeue에서는 xmltype 페이로드를 원하는 객체 유형으로 변환하는 다른 변환을 지정할 수 있습니다. 아래는 예 : 우리는 우리의 로컬 및 원격 데이터베이스에 사용합니다

create or replace type OBJ_MSG as object(
    id number, 
    value varchar2(4000) 
) 

:

우리는 개체 유형이 있다고 할 수 있습니다. 다음 단계는 페이로드가있는 원격 대기열을 xmltype으로 설정하는 것입니다. 다음으로 변환 함수가 필요합니다. 변환 함수는 OBJ_MSG 객체 유형을 매개 변수로 사용하고 xmltype을 반환합니다. 이 queueu하기 위해 우리는 우리의 변화와 subsriber을 만들

begin 
    dbms_transform.create_transformation(
    'LOCAL',--SCHEMA 
    'LOCAL_TRANS_TO_XML_TYPE',--Our transformation name 
    'LOCAL',--SCHEMA 
    'OBJ_MSG',--Our object name 
    'SYS', 
    'XMLTYPE',--Transformation result 
    'PACKAGE.trans_to_xml_type(source.user_data)');--function name, which takes payload as a parameter 
end; 
/

다음을 추가 :

function trans_to_xml_type(
    p_payload in OBJ_MSG) 
    return xmltype is 

    cursor c_trans_payload(
    cp_id number, 
    cp_value varchar2) is 
    select 
    xmlelement(
     "envelope", 
     xmlelement(
     "id", cp_client), 
     xmlelement(
     "value", cp_value)) 
    from 
    dual; 

    l_return xmltype; 
begin 
    open c_trans_payload(
    p_payload.id, 
    p_payload.value); 
    fetch c_trans_payload 
    into l_return; 
    close c_trans_payload; 

    return l_return; 

    exception 
    when others then 
     raise_application_error(-20001, '.trans_to_xml_type .Failed to transform OBJ_MSG payload to sys.xmltype: ' || sqlerrm); 
end; 

다음으로, 우리는 우리의 변환을 만들

declare 
    l_agent sys.aq$_agent := sys.aq$_agent(
    name => 'local_agent', 
    address => '[email protected]_DB', 
    protocol => 0); 
begin 
    dbms_aqadm.add_subscriber(
    queue_name => 'LOCAL.LOCAL_QUEUE', 
    subscriber => l_agent, 
    transformation => 'LOCAL_TRANS_TO_XML_TYPE', 
    queue_to_queue => true); 
end; 
/

그래서 지금 우리는 우리의 온도에 전파를 예약 열. 전파되는 메시지의 객체 유형은 xmltype으로 변환되어 원격 임시 대기열에 대기열에 포함됩니다. 원격 DB에서 dbms_scheduler 작업을 작성하십시오.이 작업은 지정된 변환을 사용하여 주기적으로 메시지를 큐에서 제거하고 원격 대상 대기열에 대기열에 넣습니다.