问题
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