#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. Этот комментарий не содержит достаточно подробностей, чтобы быть полезным