Не удается поставить в очередь большие текстовые сообщения в Oracle AQ через JMS-клиент — ORA-00942: таблица или представление не существует

#oracle #jdbc #jms #clob #oracle-aq

#Oracle #jdbc #jms #clob #oracle-aq

Вопрос:

Я ставлю в очередь сообщения JSON в Oracle AQ на JVM через JMS-клиент. Это нормально работает для небольших текстовых сообщений, но не работает для больших сообщений. Я считаю, что это как-то связано с использованием Oracle VARCHAR для небольших сообщений и переключением CLOB на сообщения размером более 4000 символов.

Сценарий базы данных 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 как

 <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
  

Ответ №1:

Мне удалось ввести точку останова, AQjmsUtil.writeClob и я мог видеть, что исключение генерируется для следующего

 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 Логика выполняет an UPDATE , тогда как для меньших строк, где VARCHAR используется, я считаю, что это делает только an INSERT . Оскорбительное UPDATE утверждение было

 UPDATE MY.AQT_MY_INBOX tab set tab.user_data.text_lob = ? where tab.msgid = ?
  

Проблема была устранена путем выполнения следующего GRANT сценария

 GRANT SELECT, UPDATE ON MY.AQT_MY_INBOX TO MY_USER;
  

Странная особенность этого решения заключается в том, что мне не нужен INSERT грант для этой таблицы (есть только ENQUEUE грант для вышележащей очереди). Я чувствую, что это небольшая ошибка в реализации oracle, и что гранты INSERT и UPDATE должны быть добавлены ENQUEUE грантом. Либо это, либо JMS API должен выполнять single INSERT , а не UPDATE for CLOB (аналогично тому, как VARCHAR это реализовано)

Комментарии:

1. Все, что я сделал, это перезапустил скрипт liquibase с именем таблицы в верхнем регистре!

2. Этот комментарий не содержит достаточно подробностей, чтобы быть полезным