3

用例是发送 JMS 消息的设备,其中包含由 MDB 处理的 GPS 信息。如果数据库中不存在设备,则创建/插入它并创建/插入 GPS 记录。当消息在发送时得到处理时,一切正常。当来自同一设备的消息在彼此之间建立并在几毫秒内处理时,就会出现此问题。在另一个 JMS 进程检查实体(并且它不存在)和尝试插入实体(并且它已经存在)的时间之间,似乎存在一个 JMS 消息进程插入实体的竞争条件。

该进程正在尝试多次插入设备实体,因为在某些时候该进程发现不存在任何记录。引发以下异常,因为该记录已由正在处理的先前消息插入。我尝试将 IsolationLevels 更改为 SERIALIZABLE 的每个值,但没有成功。任何想法将不胜感激!WAS 7、OpenJPA 2.0.2、EJB3.0

[8/30/12 11:14:01:319 EDT] 0000002a RegisteredSyn E   WTRN0074E: Exception caught
  from before_completion synchronization operation:
  <openjpa-2.0.2-SNAPSHOT-r422266:1295351 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.

Caused by: <openjpa-2.0.2-SNAPSHOT-r422266:1295351 fatal store error>
  org.apache.openjpa.persistence.EntityExistsException: ORA-00001:
  unique constraint (SPW_OWN.PK_DEVICE) violated

执行此过程的 SSB 片段:

                Device device = deviceManager.findDeviceByDeviceI(deviceString);

                //check to see if device entity exists
                if(device == null){
                    Log.logDebug(this, "device " + deviceString +" is null");

                    device.setDeviceI(deviceString);

                    //tried both create and update with no luck
                    //deviceManager.createDevice(device);

                    deviceManager.updateDevice(device);
                }

JPA 单边带:

@Action(Action.ACTION_TYPE.UPDATE)
public String updateDevice(Device device) throws Exception {
    EntityManager em = getEntityManager();
    try {
        device = em.merge(device);
    } finally {
        em.close();
    }
    return "";
}

做一些测试,我找到了一份体面的工作,尽管我仍然不是 100% 满意。欢迎任何其他建议:

  • 将 JMS MDB 设置为 Bean Managed 事务类型,并将其他后续 SSB 保持在 Container 模式,以便我仍然可以管理 Container 以进行回滚的实际数据操作。
  • 在 MDB 中设置编程阈值以重试和处理消息 X 次。
  • 调用 SSB 时捕获 EJBTransactionRolledbackException(由 EntityExistsException 引起)
  • 使用阈值再次重试处理消息(在我的情况下第二次成功,因为之前的事务已提交,重试发现实体存在并成功处理消息)
  • 我以编程方式设置了我的阈值,以在将消息发送到错误队列之前尝试处理消息两次。

我通常不喜欢使用异常捕获作为控制流。我还想象有一种方法可以将 JMS MDB 保持为容器管理事务并让 Java EE 服务器重新处理消息。

4

0 回答 0