Websphere将虚拟(已处理)异常发布到日志中

时间:2015-07-16 15:37:57

标签: java-ee exception-handling websphere websphere-8

在我们的环境中,我们从队列中获取大量消息并异步处理它们。对于每条消息,我们需要在数据库中创建或查找一行。我们遵循典型的create-get模式来处理两个线程正在寻址同一个" parent"对象:

public void ensure(Data d) {
  try {
    o = dao.create(d);
    log("Created");
  }
  catch(Exception x) {
    o = dao.get(d);
    if(o != null) {
      log("Existed");
    }
    else {
      event("Couldn't create or get parent!");
    }
  }
}

这种方法100%有效。我总是在数据库中看到预期的对象,从来没有看到"无法创建"信息。优异。

关于这个的丑陋部分是,即使捕获并处理了对象已经存在时从create中抛出的异常,我仍然在日志中看到异常,这可以理解地造成一些混淆:

[7/16/15 11:11:37:930 EDT] 0000003b RegisteredSyn E   WTRN0074E: Exception caught from before_completion synchronization operation: <openjpa-2.1.2-SNAPSHOT-r422266:1636464 fatal store error> 

org.apache.openjpa.persistence.EntityExistsException: The transaction has been rolled back.  See the nested exceptions for details on the errors that occurred.
<Exception stacktrace omitted>
[7/16/15 11:11:37:942 EDT] 0000003b SystemOut     O Existed

抱歉,由于安全问题,我无法发布整个堆栈跟踪。

知道如何让这个幻影异常停止显示在日志中吗?

编辑以添加更多代码:

DAO:

public Data create(Data d) {
  UserTransaction utx = context.getUserTransaction();

      try {
        utx.begin();
        em.persist(d);
        utx.commit();
      }
      catch(Exception x) {
        throw MyException(x);
        // also tried simply returning null
      }
      // also tried catching Throwable
      return d;
    }

1 个答案:

答案 0 :(得分:0)

假设在事务上下文中调用ensure(可能是因为它是EJB),只要从dao.create抛出异常,就会收到此日志消息。

EntityManager.persist(...)中的失败导致当前事务被标记为回滚。

因此,即使您发现了异常,WebSphere也会警告您未提交您的事务。如果您对o进行了任何更改,则不会保留这些更改。

此行为是设计使然,所有应用服务器都会执行此类操作,因为JavaEE规范要求它。基本上,任何转义EJB方法调用的java.lang.RuntimeException都会自动标记当前事务以进行回滚。

如果您不希望发生这种情况,那么您应该在DAO中捕获它并改为抛出一个已检查的异常。

进一步阅读后修改

根据JPA规范,事务被persist操作标记为回滚。因此,您需要安排create方法在其自己的事务中运行。通常这可以通过以下方式完成:

@TransactionAttribute(REQUIRES_NEW)
public Data create(Data d) throw MyException {
    try {
       em.persist(d);
    } catch (PersistenceException e) {
       throw new MyException(x);
    }
    return d;
}

由于上述原因,您仍需要检查例外。

顺便说一下,我们通常不会使用UserTransaction对象,因为默认情况下我们会获得容器管理事务(CMT)。