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

我有以下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上,如果我在MessageDrivenContext上调用context.setRollbackOnly()并结束处理而不抛出异常,则会在非常非常短的时间间隔内无限地重新传递消息.所以这对我来说是没有选择的.

如果我抛出RuntimeException,则会根据我的指定重新传递消息.它以1秒的间隔重新传送5次.但就我而言,我根本不想重试处理.

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

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

最佳答案
我看到两个选择:

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

转载注明原文:java – 在MessageDrivenBean中将事务标记为仅回滚,而不重试该消息 - 代码日志