EJB事务回滚后自动重试

4

基本上,我有一个JMS队列和一个MDB来收集来自JMS队列的消息,对它们进行一些处理,然后通过JPA将消息持久化到数据库中。我标记了负责将消息持久化到数据库中的方法以在新事务中启动:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void create(T entity)
{
    try
    {
        getEntityManager().persist(entity);
    }
    catch(Exception e)
    {
        throw new RuntimeException("DB Exception");
    }
}

如果事务被回滚,它会自动重新尝试直到事务完成吗?如果不会,如何启用该功能?
1个回答

5
如果异常传播到MDB,事务将不会提交,消息也不会被确认为已接收并进行重试。根据EJB 3.1规范:

消息确认由容器自动处理。如果消息驱动bean使用容器管理的事务划分,则消息确认作为事务提交的一部分自动处理。

我不熟悉Weblogic,但应该有一个JMS队列参数设置重试次数,重试间隔等等,直到消息被丢弃或放在未传送队列中。
但通常最好在MDB中捕获异常,因为从MDB抛出的RuntimeException将导致容器丢弃该bean。根据EJB 3.1规范:

通常情况下,消息驱动bean不应引发RuntimeExceptions。

来自message listener方法和容器调用的回调(包括消息驱动bean类的任何方法)的非应用程序异常引发的运行时异常会导致状态转换为“不存在”。

例如,最好这样写:
public class MyMDB implements MessageListener {

  @Resource
  private MessageDrivenContext context;

  public void onMessage() {
     try {
        //some other processing
        someService.create(entity);
     }
     catch(Exception e) {
        //mark the message as undelivered
        context.setRollbackOnly();
     }
  }
}

你的onMessage方法应该处理所有异常。抛出RuntimeException被认为是编程错误。如果有人需要参考,请查看:http://docs.oracle.com/javaee/7/tutorial/jms-concepts003.htm。 - mambolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接