我们同时完成数据库和JMS处理是聪明还是幸运?

Is our simultaneous completion of database and JMS processing smart or lucky?

我们使用 JMS 在 Java 1.8 SE 环境中处理消息。消息源自 Oracle (12) 高级队列。

我们想从 JMS 队列中读取一条消息,根据它做一些工作,并将结果保存在数据库中。我们不想丢失任何消息,也不想重复处理任何消息。换句话说,我们希望 JMS 消息和关联数据库的处理 activity 成为单个事务。

我们已经阅读了有关如何执行此操作的各种文章(包括 Transaction and redelivery in JMS, JMS Message Delivery Reliability and Acknowledgement Patterns, Reliable JMS with Transactions)。共识似乎是使用 JTA/XA,但我们希望使用更简单的东西。

我们使用 Oracle 的 Advanced Queuing 作为我们的 JMS 提供程序,因此我们决定看看是否可以对 JMS 和数据库使用相同的数据库连接 activity,以便一次提交对两个 JMS 都有效和数据库 activity。好像有效果。

在下面的代码中,我们在初始化 JMS 队列时使用现有的 SQL 连接创建了一个 QueueConnection。处理消息后,提交 JMS 会话也会提交数据库更改。 我们还没有看到其他地方讨论过这种方法,所以我们想知道

  1. 我们有适用于 Oracle Advanced 的可靠解决方案 排队,
  2. 我们有一个解决方案恰好可以解决某些问题 该版本的 Oracle Advanced Queueing 的时间到了,
  3. 我们刚刚得到 我们的测试用例真的非常幸运,这种方法充满了问题 有危险

请评论我们的方法是否可靠或我们是否应该使用 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

鉴于 processMessage 使用 dbConnection class 属性,看来您对 JMS 和 OAQ 的假设是正确的。

https://docs.oracle.com/javaee/7/api/javax/jms/QueueConnection.html

所以,回答你的问题:是的,你有一个可靠的解决方案(假设我之前提到过)。