Можно ли вывести очередь из очереди синхронного захвата ANYDATA с использованием JDBC?

То, что я пытаюсь сделать, это подписаться на все изменения в таблице Oracle, используя синхронный захват из процесса Java.

Очередь ANYDATA создается с

BEGIN
  DBMS_STREAMS_ADM.SET_UP_QUEUE(
    queue_table  => 'hcb_qtab_any',
    queue_name   => 'hcb_queue_any',
    queue_user   => 'gguser');
END;

А потом я использую код из Dequeue, используя Java для очереди Oracle 11g в качестве примера. Я пытаюсь сделать

message = queue.dequeue(deq_option, XMLType.getORADataFactory());

Но все, что я получаю, это oracle.AQ.AQOracleSQLException: Ошибка создания дескриптора: Invalid arguments, Оказывается, я немного отладил это для ANYDATA. TypeDescriptor.getTypeDescriptor() вернет OpaqueDescriptor, который не считается StructDescriptor.isValidObject(),

Я сделал еще один дубль, используя тонкий JDBC AQ:

AQDequeueOptions deqopt = new AQDequeueOptions();
deqopt.setConsumerName("subscriber1");
AQMessage msg = conn.dequeue("hcb_queue_any", deqopt, "SYS.ANYDATA");
OPAQUE opq = (OPAQUE)msg.getANYDATAPayload().accessDatum();

И здесь я сталкиваюсь с новой уникальной проблемой. Этот OPAQUE имеет getDescriptor().getTypeName() == "XMLTYPE", поэтому я бы очень хотел превратить его в XML. Но есть проблема: только тонкий драйвер JDBC поддерживает AQ, в то время как только драйвер ACI поддерживает преобразование OPAQUE в XML. я собираюсь Only LOB or String Storage is supported in Thin XMLType ошибка, когда я пытаюсь сделать new XMLType(opq)

Как получить Synchronous Capture XML из AQ с использованием JDBC?

1 ответ

Решение

Вы можете написать хранимую процедуру и удалить сообщение из очереди в PL/SQL, преобразовать его в текст XML и вернуть как CLOB. Затем вы можете вызвать хранимую процедуру из Java с помощью JDBC. Я использовал подобный обходной путь раньше, когда в простом API AQ отсутствовала функция.

Пример:

create or replace procedure dequeue_lcr(
    p_queue_name   varchar2,
    p_consumer     varchar2,
    p_wait_seconds number,
    p_lcr          out clob) as
  deq_lcr     anydata;
  deq_xml     xmltype;
  msgid       raw(16); 
  deqopt      dbms_aq.dequeue_options_t; 
  mprop       dbms_aq.message_properties_t;
  no_messages exception; 
  pragma exception_init (no_messages, -25228);
begin
  deqopt.consumer_name := p_consumer;
  deqopt.wait := p_wait_seconds;
  deqopt.navigation := dbms_aq.first_message;
  deqopt.dequeue_mode  := dbms_aq.remove;
  begin
    dbms_aq.dequeue( 
      queue_name         =>  p_queue_name,
      dequeue_options    =>  deqopt,
      message_properties =>  mprop,
      payload            =>  deq_lcr,
      msgid              =>  msgid);
     deq_xml := dbms_streams.convert_lcr_to_xml(deq_lcr);
     p_lcr := deq_xml.getclobval();    
     commit;
  exception
    when no_messages then
      p_lcr := null;
  end;
end;

Это работает, когда я вызываю его из PL/SQL с правильной очередью и потребителем:

declare
  v_clob clob;
begin
  dequeue_lcr('aqtest.hcb_queue_any', 'LOCAL_AGENT', 5, v_clob);
  if (v_clob is not null) then
    dbms_output.put_line('Data: ' || v_clob);
  else
    dbms_output.put_line('No messages');  
  end if;
end;

Просто сделайте вызов из Java с CallableStatement с clob в качестве выходного параметра, и все будет хорошо!

Другие вопросы по тегам