在ExchangeDrivenBean中将事务标记为仅回滚,而不重试该消息

时间:2012-01-06 17:35:34

标签: java java-ee transactions message-queue

我有以下MessageDrivenBean:

@MessageDriven(mappedName = "jms/...", activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryAttempts", propertyValue = "5"),
    @ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryInterval", propertyValue = "1000")
})
public class MyMessageListener implements MessageListener {

    @Resource
    private MessageDrivenContext context;

    @Override
    @TransactionAttribute(REQUIRED)
    public void onMessage(Message message) {            
    }
}

onMessage方法中,我做了一些在这里不重要的处理。在某些情况下,我想放弃处理。在那种情况下,我想将事务标记为仅回滚,并且不想重试处理。

至少在Glassfish 3.1.1上,如果我在context.setRollbackOnly()上调用MessageDrivenContext并结束处理而不抛出异常,则会在非常非常短的时间间隔内无限地重新传递消息。所以这对我来说是没有选择的。

如果我抛出RuntimeException,则会按照我的指定重新传递该消息。它以1秒的间隔重新传送5次。但在我的情况下,我根本不想重试处理。

如果我只是结束处理而不抛出任何异常并且没有调用context.setRollbackOnly(),那么就像人们所期望的那样提交事务。但是我需要回滚事务,因为我可能已经改变了一些JPA实体。

我的问题是:如何在不触发消息重新传递的情况下将事务标记为仅回滚?

1 个答案:

答案 0 :(得分:1)

我看到两个选项:

  1. 使用@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)注释bean,使用bean管理的事务而不使用AUTO_ACKNOWLEDGE(在MDB中显式确认消息)。如果您的MDB是更大的XA交易的一部分,则不是一个选项,您将没有机会影响全局交易结果。
  2. 检查邮件上的getJMSRedelivered()标记,然后丢弃重新传递的邮件。这里的问题是,在重新传递时你不知道它是否是你应该忽略的重新传递(你说在某些情况下你确实想重试处理) - 你必须暂时存储(在数据库或缓存中)id处理失败的消息,因此您知道是否可以安全地忽略它们。