无法通过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

查看:115
本文介绍了无法通过JMS客户端将大型文本消息排队到Oracle AQ上-ORA-00942:表或视图不存在的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过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实现中的一个错误,并且INSERTUPDATE授予都应该由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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆