Можно ли вывести очередь из очереди синхронного захвата 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 в качестве выходного параметра, и все будет хорошо!