【问题标题】:Java EE Persistence Exception with thread race condition and requires_new transaction attribute具有线程竞争条件和 requires_new 事务属性的 Java EE 持久性异常
【发布时间】:2012-01-17 05:48:07
【问题描述】:

我有一个附加了 REST Web 服务的 Java EE 应用程序。每个 REST 调用都有自己的无状态 bean 进行操作。这个 bean 调用一个辅助 bean 来创建新项目并将它们持久保存在数据库中。当 REST bean 取回项目时,稍微对其进行操作,然后将其合并到数据库中。这是一般流程

// Bean A
void someRESTCall()
{
    Item i = beanB.getItem(...);

    // Possible race condition here
    if(i == null)
    {
       i = beanB.buildItem();
       if(i == null)
       {
          // Assume race condition
          i = beanB.getItemForce(...); // This has transactional attribute REQUIRES_NEW
       }
    }

   // Do some stuff to the item and merge it
   i.setColor("blue");
   entityManager.merge(i);

}

// Bean B
Item buildItem(...)
{
   Item i = new Item();
   i.setName(name); // Name is the primary key, cannot be changed.   

   try
   {
       entityManager.persist(i);
   }
   catch(PersistenceException ex)
   {
     // Assume threading issue / race condition
     i = null;
   }

   return i;
}

我们最初遇到的问题是,如果两个 rest 调用进入竞争条件,您可能在数据库中有重复项(这会导致约束异常,因为主键不是自动生成的。)

所以,为了解决这个问题,我将返回 null 添加到 buildMachine。问题是事务回滚了,虽然A继续执行,但是回滚后不能正常更新数据库。

所以为了解决这个问题,我尝试在 buildMachine 方法中添加一个 REQUIRES_NEW 事务属性。当我这样做时,当 beanA 去合并它的更改时,我得到一个约束异常。

那么,我怎样才能绕过竞争条件和约束异常呢?也许更重要的是,为什么调用合并会导致约束异常?它应该重用buildItem返回的现有项目数据库行,更改数据库以允许自动生成主键不是一种选择。

有些人建议删除 beanA 中对 entityManager.merge() 的调用,说它是/曾经是多余的。如果我这样做,A 所做的任何更改都不会被合并。

【问题讨论】:

    标签: jakarta-ee jboss ejb


    【解决方案1】:

    你有几个问题。

    第一个问题:persist() 没有插入数据库。它只会附加一个瞬态实体。插入仅在 flush(à 被调用时执行,在事务提交之前显式或隐式地执行。捕获持久性抛出的异常将不起作用

    第二个问题:由于A.someRESTCallB.buildItem在同一个事务中运行,如果JPA抛出任何异常,你唯一能做的就是回滚事务并丢弃会话。抛出任何异常后,Hibernate 会话处于不稳定状态,您无法从它抛出的任何异常中恢复。

    所以,我会做的是:

    • 从数据库中获取项目
    • 如果有,更新(这里不需要调用merge:实体已附加)并返回
    • 如果没有,调用带有 requires_new 事务的方法来创建和更新项目
    • 如果此方法成功,则返回。
    • 如果此方法抛出异常,则返回步骤 1。

    【讨论】:

    • 谢谢,我可以通过将REQUIRES_NEW 添加到getItembuildItem 来修复它。我通常在 .NET 中开发,所以这种使用模式对我来说很奇怪......我不太喜欢 Hibernate 如何假设“你无法从异常中恢复”——但是——这就是生活,感谢提示。
    猜你喜欢
    • 2012-11-17
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多