如何使JMS消息发送给MQ完全提交?

时间:2014-03-28 16:36:22

标签: java jms java-ee-6 ibm-mq

我在Websphere Application Server上部署了一个EAR,它使用一个函数通过使用JMS向MQ发送消息,并从另一个队列中立即收到消息。

    ConnectionFactory cf = null;
    InitialContext context = null;
    String[] arrDatos_SR = null;

    Connection conn = null;
    Session session = null;
    Queue queue = null;
    Queue queue2 = null;

    Destination dest = null;
    Destination dest2 = null;
    MessageConsumer consumer = null;
    MessageProducer producer = null;
    TextMessage message = null;

    String comando = "";
    int tamanio = 0;
    String tamanio2 = "";
    String cadena = "";

    try {
        context = new InitialContext();
        cf = (ConnectionFactory) context.lookup(arrDatos[1].trim());
        conn = cf.createConnection();
        session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);      
        queue = (Queue) context.lookup(arrDatos[2].trim());
        queue2 = (Queue) context.lookup(arrDatos[3].trim());
        dest = (Destination) queue;
        dest2 = (Destination) queue2;

        producer = session.createProducer(dest);


        // Create a text message using the queue session.
        TextMessage textMessage = session.createTextMessage();

        textMessage.setText(arrDatos[4]);

        textMessage.setJMSReplyTo(dest2);
        textMessage.setJMSMessageID(arrDatos[6]);
        textMessage.setJMSCorrelationID(arrDatos[7]);
        producer.send(textMessage);


    } catch (NamingException e) {
        // TODO Auto-generated catch block
        logger.error("MQSendReceive() - Exception e2 = "
                + e, e);
    } catch (JMSException e) {
        // TODO Auto-generated catch block
        logger.error("MQSendReceive() - Exception e2 = "
                + e, e);
    } 

        arrDatos[5] = arrDatos[5].trim();

        try{
            conn.start();       
            consumer = session.createConsumer(dest2);
            Message receivedMessage = consumer.receive(Long.parseLong(arrDatos[5]) * 1000);



            if(receivedMessage != null)
            {
                message = (TextMessage)receivedMessage;
                comando = message.getText();
                comando = comando.trim();
                tamanio = comando.length();
                tamanio2 = StringUtils.leftPad(Integer.toString(tamanio), 9, '0');

                comando = StringUtils.rightPad(comando, Constantes.TAMANIO_RESPUESTA_DES_C1, ' ');
                cadena = arrDatos[0] + comando + tamanio2; 
            }
            else
            {
                comando = new String();
                comando = "";
                tamanio = comando.length();
                tamanio2 = StringUtils.leftPad(Integer.toString(tamanio), 9, '0');

                cadena = arrDatos[0] + comando + tamanio2;
            }

            arrDatos_SR = new String[2];
            arrDatos_SR[0] = cadena;
            arrDatos_SR[1] = arrDatos[0];

        }
        catch(Exception e)
        {
            logger.error("MQSendReceive() - Excepcion:" + e);
        }
        finally
        {
            try {
                consumer.close();
                session.close();
                conn.close();
                context.close();
            } catch (JMSException e) {
                // TODO Auto-generated catch block
                logger.error("MQSendReceive() - Error desconectando de MQ - Excepcion:" + e);
            } catch (NamingException e) {
                // TODO Auto-generated catch block
                logger.error("MQSendReceive() - Error desconectando de MQ - Excepcion:" + e);
            }

        }

        return arrDatos_SR;

消息被发送到MQ队列#1,然后将其传送到另一个MQ队列#2,这是另一个MQ队列#3的传输队列。我使用Websphere MQ管理GUI测试将消息放入此队列,并且它们可以顺利传输。但是当我出于某种原因使用我的代码时,发送不会立即发送。相反,它是在接收结束后(超时到期或实际收到消息时)完成的

有人可以告诉我为什么会这样吗?

更新 :( 2014年3月31日)我忘了提到我正在使用带有@LocalBean,@ Singleton和@TransactionManagement(TransactionManagementType.CONTAINER)注释的EJB容器。通过从SO(http://goo.gl/JBSW7r)阅读这篇文章,我意识到我有3个类可以构成整个连接,还有一个主要使用它们作为我使用公共方法的对象。我决定使用相同的注释将这些类转换为EJB。我还尝试将每个方法的@TransactionAttribute类型一次更改为REQUIRED,NOT SUPPORTED和MANDATORY,只是为了测试其中一些是否有效。我还将会话行更改为:

session = conn.createSession(true, Session.SESSION_TRANSACTED); 

结果似乎是一样的。在MessageConsumer的超时间隔期间收到消息时,消息仍然卡在传输队列中。

有人能给我一些关于这些的东西吗?

3 个答案:

答案 0 :(得分:3)

根据您对问题的描述,我相信您提供的代码是在具有容器管理事务的EJB的上下文中执行的。在Java EE应用程序服务器中,JMS操作将由事务协调。这意味着在EJB方法结束时容器提交事务之前,send实际上不会完成。

虽然在Java EE应用程序服务器中创建会话时设置为false,但会忽略该会话,并且会话将在任何有效的全局事务中注册。

此问题的解决方案是确保在没有事务的情况下执行JMS发送。为此,应使用事务类型NOT_SUPPORTED配置EJB方法。

答案 1 :(得分:1)

经过这么多尝试,我结束了删除EJB。我用整个逻辑制作了一个web项目。我决定通过使用带有while循环的Thread来控制代码的重复。我使用布尔变量来控制EAR启动和关闭时while循环的初始化和停止。

好吧,回到Web应用程序,它可以正常工作。我不知道为什么它以这种方式工作而不是另一种,但我认为现在没问题。

答案 2 :(得分:1)

虽然看起来OP通过将他的逻辑转移到Web模块而得到了一个解决方案,但是我想在其他人需要使用EJB的情况下添加一个潜在的选项。

Alasdair的答案绝对是将EJB类型逻辑移回Web应用程序的首选方式。我们刚刚在创建新的EJB 3.0项目并定义发送消息并等待来自Websphere MQ的回复的bean时遇到此问题。我们发现我们确实在开始时使用事务类型Container定义了我们的会话bean,由于前面提到的确切原因而失败了。

将事务类型切换为 Bean ,然后为我们解决了这个问题。它仍然允许会话bean保留一些事务属性,但也让JMS发送一个已提交的消息。