是否可以使用 JDBC 从 ANYDATA 同步捕获队列中出队?

Is it possible to dequeue from ANYDATA Synchronous Capture queue using JDBC?

我想做的是使用 Synchronous Capture 从 Java 进程订阅 Oracle table 中的所有更改。

ANYDATA 队列是用

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

然后我使用 Dequeue using Java for Oracle 11g queue 中的代码作为示例。我正在努力

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

但我得到的只是 oracle.AQ.AQOracleSQLException:创建描述符时出错:Invalid arguments。事实证明,我对它进行了一些调试,因为 ANYDATA TypeDescriptor.getTypeDescriptor() 将 return 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。当我尝试执行 new XMLType(opq)

时出现 Only LOB or String Storage is supported in Thin XMLType 错误

如何使用 JDBC 从 AQ 中获取 Synchronous Capture XML

您可以编写一个存储过程并使 PL/SQL 中的消息出列并将其转换为 XML 文本和 return 作为 CLOB。然后您可以使用 JDBC 从 Java 调用存储过程。当普通 AQ API 缺少功能时,我之前使用过类似的解决方法。

示例:

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;

只需使用带有 clob 作为输出参数的 CallableStatement 从 Java 进行调用,您就可以开始了!