JPA事务回滚重试和恢复:合并具有自动递增的@Version的实体

我想在交易失败后恢复。

现在,当然,在进行任何回滚之后,所有实体都将分离,并且实体管理器将关闭。 但是,UI仍保留分离的实体。 显然,我们不能只是丢弃用户的更改,所以我们想让他们重试(修复突出显示的验证错误,然后再次单击按钮)。

跟随 Java 持久性WikiBook

错误处理的一种方法是,在提交失败到新的EntityManager后,为每个受管理对象调用合并,然后尝试提交新的EntityManager。 一个问题可能是,已分配的所有ID或已分配或递增的乐观锁版本都可能需要重置。 另外,如果原始EntityManager是EXTENDED,则所有正在使用的对象仍然会分离,并且需要重置。

此选项乍一看似乎很简单,直到我们不可避免地遇到这些预期的问题为止。 某些服务可能由于各种原因而触发刷新,这会使DB(回滚)和Java实体(非回退)中的 @Version 字段增加。 下一个“保存”调用 merge ,这将引发意外的 OptimisticLockException

是否存在一种可靠的方法来“回滚” Java实体bean中的版本字段?

确定 ,很难缝合。 我们将实体与自己的@Versions级联,因此手动进行操作似乎很脆弱。 (无论如何我们怎么能可靠地知道原始(持久性)版本?无法查询,因为其他用户可能会同时成功更新实体;查询当前版本可能会破坏锁定!)

另一种涉及更多方法 错误处理始终与非事务性EntityManager一起使用。 提交时,将创建一个新的EntityManager,将非事务性对象合并到其中,并提交新的EntityManager。 如果提交失败,则只有新EntityManager的状态可能不一致,原始EntityManager不会受到影响。 这样可以解决问题,并将EntityManager重新合并到另一个新的EntityManager中。 如果提交成功,则可以将所有提交更改重新合并回原始的EntityManager,然后可以继续正常使用它。 此解决方案需要相当大的开销,因此仅在确实需要错误处理且JPA提供程序没有替代方法的情况下才应使用。

这似乎合乎逻辑。 有没有人有使用两个EntityManager(尤其是Spring)实施这种恢复的经验? 在尝试它之前,我应该意识到任何陷阱吗?似乎每个服务和DAO现在都必须意识到两个实体管理器(对于Spring,今天,它们几乎与持久层无关)。 DAO的“查找”操作使用一个EM。 “更新”使用另一个。 或者具有单独的“读取”和“写入” DAO。 Ouch。

我考虑过的其他选项包括:

  • 在UI中使用DTO,因此自动递增不会影响任何事情。 丑陋。
  • 将调用移到任何组合操作的合并。 仅在所有验证和状态更新成功后才附加实体。 “保存”服务将不再合并(仅验证)似乎很奇怪。 实际上,UI将负责调用DAO!

建议?谢谢:-)

更新 我的体系结构包括:

  • 由UI(JSF)更新的已分离实体
  • 实体ID不会自动生成(预先分配的UUID和/或业务密钥)
  • 实体已自动递增 @Version 字段用于oplocking
  • “保存”服务验证,调用 em.merge (基于Hibernate的JPA)
  • “ Process”服务验证,应用业务逻辑,更新实体状态
  • 可以组成服务 。 一个UI按钮可能会起作用
    1. (围绕UI控制器的Spring @Transactional 建议:开始
    2. 保存
    3. 进程1
    4. 进程2
    5. @Transactional commit
  • 任何服务都可能引发验证异常(JSR 303),该异常会按预期回滚(消息在UI中显示)

7
задан Peter Davis 26 June 2011 в 06:45
поделиться