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

夙愿已清 提交于 2019-12-25 03:17:06

问题


What I'm trying to do is subscribe to all changes in Oracle table using Synchronous Capture, from Java process.

ANYDATA queue is created with

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

And then I'm using code from Dequeue using Java for Oracle 11g queue as an example. I'm trying to do

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

But all I get is oracle.AQ.AQOracleSQLException: Error creating descriptor: Invalid arguments. I've debugged it a bit, it turns out, for ANYDATA TypeDescriptor.getTypeDescriptor() will return OpaqueDescriptor which isn't considered as StructDescriptor.isValidObject().

I did another take using thin 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();

And I'm facing a new unique problem here. This OPAQUE has getDescriptor().getTypeName() == "XMLTYPE", so I would very much like to turn it to XML. But there's a problem: Only thin JDBC driver supports AQ, while only ACI driver supports turning OPAQUE to XML. I'm getting Only LOB or String Storage is supported in Thin XMLType error when I'm trying to do new XMLType(opq)

How do I get Synchronous Capture XML from AQ using JDBC?


回答1:


You could write a stored procedure and dequeue the message in PL/SQL and convert it to XML text and return it as a CLOB. Then you can call the stored procedure from Java with JDBC. I have used a similar workaround before when the plain AQ API lacked a feature.

Example:

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;

This works when I call it from PL/SQL with the proper queue and consumer:

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;

Just make the call from Java with a CallableStatement with a clob as output parameter and you should be good to go!



来源:https://stackoverflow.com/questions/49634691/is-it-possible-to-dequeue-from-anydata-synchronous-capture-queue-using-jdbc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!