无法通过JMS客户端将大型文本消息排队到Oracle AQ上-ORA-00942:表或视图不存在 [英] Can't enqueue large text messages onto Oracle AQ via JMS client - ORA-00942: table or view does not exist
问题描述
我正在通过JMS客户端将JSON消息排队到JVM上的Oracle AQ上.对于小文本消息,此方法工作正常,但对于大消息,则失败.我相信这与Oracle有关,它使用VARCHAR
表示较小的消息,并切换到CLOB
表示大于4000个字符的消息.
I am enqueuing JSON messages onto Oracle AQ on the JVM via the JMS client. This is working fine for small text messages but is failing for larger messages. I believe that this is something to do with Oracle using VARCHAR
for smaller messages and switching to CLOB
for messages larger than 4000 characters.
AQ数据库脚本是
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE (
queue_table => 'MY.AQT_MY_INBOX',
queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE',
comment => 'QueueTable for MY Inbox Messages',
multiple_consumers => FALSE,
sort_list => 'priority,enq_time'
);
DBMS_AQADM.CREATE_QUEUE (
queue_name => 'MY.AQ_MY_INBOX',
comment => 'Queue for MY Inbox Messages',
queue_table => 'MY.AQT_MY_INBOX',
queue_type => SYS.DBMS_AQADM.NORMAL_QUEUE,
max_retries => 2880,
retry_delay => 30
);
DBMS_AQADM.GRANT_QUEUE_PRIVILEGE(
privilege => 'ENQUEUE',
queue_name => 'MY.AQ_MY_INBOX',
grantee => 'MY_USER'
);
DBMS_AQADM.START_QUEUE (
queue_name => 'MY.AQ_MY_INBOX'
);
END;
/
oracle依赖项通过Maven配置为
The oracle dependencies are configured via Maven as
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>18.3.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>aqapi_g</artifactId>
<version>11.2.0.4</version>
</dependency>
异常堆栈跟踪为
Caused by: oracle.jms.AQjmsException: ORA-00942: table or view does not exist
at oracle.jms.AQjmsUtil.writeClob(AQjmsUtil.java:640)
at oracle.jms.AQjmsTextMessage.writeLob(AQjmsTextMessage.java:294)
at oracle.jms.AQjmsProducer.jdbcEnqueue(AQjmsProducer.java:1054)
at oracle.jms.AQjmsProducer.send(AQjmsProducer.java:747)
at oracle.jms.AQjmsProducer.send(AQjmsProducer.java:517)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:634)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:608)
at org.springframework.jms.core.JmsTemplate.lambda$send$3(JmsTemplate.java:586)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:504)
... 20 common frames omitted
Caused by: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:494)
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:446)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1052)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:537)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:255)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:610)
at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:249)
at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:82)
at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:924)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1136)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3640)
at oracle.jdbc.driver.T4CCallableStatement.executeInternal(T4CCallableStatement.java:1318)
at oracle.jdbc.driver.OraclePreparedStatement.executeLargeUpdate(OraclePreparedStatement.java:3730)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3710)
at oracle.jdbc.driver.OracleCallableStatement.executeUpdate(OracleCallableStatement.java:4265)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1061)
at oracle.jms.AQjmsUtil.writeClob(AQjmsUtil.java:605)
... 28 common frames omitted
Caused by: oracle.jdbc.OracleDatabaseException: ORA-00942: table or view does not exist
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:498)
... 44 common frames omitted
推荐答案
我能够在AQjmsUtil.writeClob
中放置一个断点,并且可以看到以下内容引发了异常
I was able to put a breakpoint in AQjmsUtil.writeClob
and I could see that the exception was being thrown for the following
clobStmt = (OracleCallableStatement)db_conn.prepareCall("UPDATE " + queueTable + " tab set tab.user_data.text_lob = ? where tab.msgid = ?");
clobStmt.setString(1, textData);
clobStmt.setBytes(2, msgid);
int count = clobStmt.executeUpdate();
CLOB
逻辑正在执行UPDATE
,而对于使用VARCHAR
的较小字符串,我相信它只在执行INSERT
.令人反感的UPDATE
语句是
The CLOB
logic is doing an UPDATE
whereas for smaller strings where VARCHAR
is used I believe it's only doing an INSERT
. The offending UPDATE
statement was
UPDATE MY.AQT_MY_INBOX tab set tab.user_data.text_lob = ? where tab.msgid = ?
通过执行以下GRANT
脚本
GRANT UPDATE ON MY.AQT_MY_INBOX TO MY_USER;
此解决方案的奇怪之处在于,我不需要此表的INSERT
授予(上面的队列只有ENQUEUE
授予).我觉得这是oracle实现中的一个错误,并且INSERT
和UPDATE
授予都应该由ENQUEUE
授予添加.要么JMS API应该对CLOB
做一个INSERT
而不是一个UPDATE
(类似于实现VARCHAR
的方式)
The strange thing about this solution is that I don't need an INSERT
grant for this table (there's only the ENQUEUE
grant for the overlying queue). I feel this is a bit of a bug in the oracle implementation and that both the INSERT
and UPDATE
grants should be added by the ENQUEUE
grant. Either that or the JMS API should do a single INSERT
and not an UPDATE
for CLOB
(similar to how VARCHAR
is implemented)
这篇关于无法通过JMS客户端将大型文本消息排队到Oracle AQ上-ORA-00942:表或视图不存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!