Наше умное или удачное одновременное завершение обработки базы данных и JMS?
Мы используем JMS для обработки сообщений в среде Java 1.8 SE. Сообщения отправляются из расширенной очереди Oracle (12).
Мы хотели бы прочитать сообщение из очереди JMS, выполнить некоторую работу на его основе и сохранить результат в базе данных. Мы не хотим терять какие-либо сообщения и не хотим дублировать обработку любого сообщения. Другими словами, мы бы хотели, чтобы обработка сообщения JMS и связанная с ним деятельность базы данных были единой транзакцией.
Мы читали различные статьи о том, как это сделать (включая транзакции и повторную доставку в JMS, шаблоны надежности доставки сообщений JMS и шаблоны подтверждения, надежные JMS с транзакциями). Похоже, консенсус заключается в использовании JTA/XA, но мы надеялись на что-то более простое.
Мы используем Oracle Advanced Queuing в качестве нашего JMS-провайдера, поэтому мы решили посмотреть, сможем ли мы использовать одно и то же соединение с базой данных как для JMS, так и для работы с базой данных, чтобы один коммит работал и для JMS, и для работы с базой данных. Кажется, сработало.
В приведенном ниже коде мы создаем QueueConnection, используя существующее соединение SQL, когда инициализируем очередь JMS. После обработки сообщения фиксация сеанса JMS также фиксирует изменения базы данных. Мы не видели, чтобы этот подход обсуждался в другом месте, поэтому нам интересно, если
- У нас есть надежное решение, которое работает для Oracle Advanced Queuing,
- У нас есть решение, которое иногда работает для этой версии Oracle Advanced Queuing,
- Нам просто очень повезло в наших тестах, и этот подход чреват опасностью.
Пожалуйста, прокомментируйте, должен ли наш подход быть надежным или мы должны использовать JTA/XA.
public class OracleJmsQueue {
private DataSource dataSource;
protected Queue queue;
protected QueueConnection queueConnection;
protected QueueReceiver queueReceiver;
protected QueueSession queueSession;
private java.sql.Connection dbConnection = null;
protected void initQueueSession()
throws JMSException, SQLException {
// Connect to the database source of messages
DataSource dataSource = getDataSource();
dbConnection = dataSource.getConnection();
dbConnection.setAutoCommit(false);
queueConnection = AQjmsQueueConnectionFactory.createQueueConnection(
dbConnection);
queueSession =
queueConnection.createQueueSession(true, Session.SESSION_TRANSACTED);
queue = ((AQjmsSession)queueSession).getQueue(queueUser, queueName);
queueReceiver = queueSession.createReceiver(queue);
}
public void run() {
initQueueSession();
// code omitted
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(200);
final Message message = queueReceiver.receiveNoWait();
if (message != null) {
processMessage(message); // alters DB tables
commitSession();
}
}
// catches omitted
}
}
protected void commitSession() throws JMSException {
logger.info("Committing " + queueName + " queue session");
queueSession.commit();
}
} // class OracleJmsQueue
1 ответ
Похоже, что ваши предположения о JMS и OAQ верны, учитывая, что processMessage
использует dbConnection
атрибут класса.
https://docs.oracle.com/javaee/7/api/javax/jms/QueueConnection.html
Итак, отвечая на ваш вопрос: да, у вас есть надежное решение (при условии, что я упоминал ранее).