我想在交易失败后恢复。
现在,当然,在进行任何回滚之后,所有实体都将分离,并且实体管理器将关闭。 但是,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将负责调用DAO! 建议?谢谢:-)
更新 我的体系结构包括:
@Version
字段用于oplocking em.merge
(基于Hibernate的JPA) @Transactional
建议:开始) @Transactional
: commit )