简体   繁体   English

读取而不从 JMS 队列中删除消息

[英]Read without removing message from JMS queue

How to read a message from WebSphere MQ without deleting the original message from queue?如何从 WebSphere MQ 读取消息而不从队列中删除原始消息?

I have spring application which reads the message from the WebSphere MQ.我有从 WebSphere MQ 读取消息的 spring 应用程序。 After reading, I have a process method which will process the data retrieved from queue.阅读后,我有一个 process 方法可以处理从队列中检索到的数据。

Step 1:第1步:

response = jmsTemplate.receive();
//Message automatically removed from queue.

Step 2:第2步:

process(response);

There are chances of throwing exceptions in process method.有可能在 process 方法中抛出异常。 In case of exceptions, I need to retain the message in the queue.如果出现异常,我需要将消息保留在队列中。

Is it possible?是否可以? Is their any way to delete the message only on user acknowledgement?他们有什么方法可以仅在用户确认后删除消息?

I tried adding the following:我尝试添加以下内容:

jmsTemplate.setSessionAcknowledgeMode(javax.jms.Session.CLIENT_ACKNOWLEDGE);

...but still the message is getting deleted. ...但消息仍然被删除。

JmsTemplate creating code snippet: JmsTemplate创建代码片段:

JndiConnectionFactorySupport connectionFactoryBean = new JndiConnectionFactorySupport();
    connectionFactoryBean.setBindingsDir(this.bindingDir);


        connectionFactoryBean
                .setConnectionFactoryName(connectionFactoryName);
        connectionFactoryBean.afterPropertiesSet();
        jmsTemplate.setConnectionFactory(connectionFactoryBean.getObject());


    JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
    destinationResolver.setJndiTemplate(connectionFactoryBean
            .getJndiTemplate());

    jmsTemplate.setDestinationResolver(destinationResolver);
    jmsTemplate.setReceiveTimeout(20000);
    jmsTemplate.setDefaultDestinationName(this.defaultDestinationName);

            

Tried the jmsTemplate.execute() method as below:尝试jmsTemplate.execute()方法如下:

@SuppressWarnings({ "unused", "unchecked" })
        Message responseMessage = (Message) jmsTemplate.execute(
            new SessionCallback() { 
                public Object doInJms(Session session)
                        throws JMSException {
                    MessageConsumer consumer = session
                    .createConsumer(jmsTemplate.getDestinationResolver().resolveDestinationName(session, "QUEUE_NAME", false));
                    Message response = consumer.receive(1);
                    try {
                        testMethod();//this method will throw exception.
                        response.acknowledge();
                        consumer.close();
                    } catch(Exception e){
                        consumer.close();//control will come here.
                    }
                    
                    return response;
                }
        }, true);

You can't do that with receive() methods because the operation is complete (from the session perspective) when the receive method returns.使用receive()方法不能这样做,因为当接收方法返回时操作已完成(从会话的角度来看)。

You need to run the code that might fail within the scope of the session;您需要运行可能在会话范围内失败的代码; eg with a JmsTemplate.execute() with a SessionCallback - something like this...例如,使用带有SessionCallbackJmsTemplate.execute() - 类似这样的......

this.jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
this.jmsTemplate.convertAndSend("foo", "bar");
try {
    String value = this.jmsTemplate.execute(session -> {
        MessageConsumer consumer = session.createConsumer(
                this.jmsTemplate.getDestinationResolver().resolveDestinationName(session, "foo", false));
        String result;
        try {
            Message received = consumer.receive(5000);
            result = (String) this.jmsTemplate.getMessageConverter().fromMessage(received);
            // Do some stuff that might throw an exception
            received.acknowledge();
        }
        finally {
            consumer.close();
        }
        return result;
    }, true);
    System.out.println(value);
}
catch (Exception e) {
    e.printStackTrace();
}

You can add transactional processing of JMS messages.您可以添加 JMS 消息的事务处理。 See the example例子

Your listener should be "transacted" .你的听众应该被"transacted" Like this像这样

<jms:listener-container connection-factory="connectionFactory" acknowledge="transacted">
    <jms:listener ref="notificationProcessor" destination="incoming.queue"/>
</jms:listener-container>

You have to browse the queue.您必须浏览队列。

Example of real code that was executed making usage of Websphere MQ使用 Websphere MQ 执行的真实代码示例

public void browseMessagesAndJiraCreation(String jiraUserName, String jiraPassword) { int counterMessages = jmsTemplate.browse(destinationQueueName, new BrowserCallback<Integer>() { @Override public Integer doInJms(final Session session, final QueueBrowser queueBrowser) throws JMSException { Enumeration<TextMessage> enumeration = queueBrowser.getEnumeration(); int counterMessages = 0; while (enumeration.hasMoreElements()) { counterMessages += 1; TextMessage msg = enumeration.nextElement(); logger.info("Found : {}", msg.getText()); JiraId jiraId = jiraManager.createIssue(jiraUserName, jiraPassword); jiraManager.attachFileToJira(jiraId, msg.getText(), jiraUserName, jiraPassword); } return counterMessages; } }); logger.info("{}:messages were browsed and processed from queue:{}.", counterMessages, destinationQueueName); }

Explanations:说明:

  • usage of the Spring Framework JmsTemplate Spring 框架 JmsTemplate 的使用
  • you pass the String gestinationQueueName (example destinationQueueName=QL.PREFCNTR.USER.REPLY)您传递字符串 gestinationQueueName(例如 destinationQueueName=QL.PREFCNTR.USER.REPLY)
  • Java enumeration of Text messages文本消息的Java枚举
  • counterMessages is the counter of messages that were processed counterMessages 是已处理消息的计数器
  • messages are NOT consumed!消息不被消耗!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM