小编Pet*_*vis的帖子

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

我想在交易失败后恢复.

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

遵循 Java Persistence WikiBook,

一种错误处理方法是在提交失败后调用每个托管对象的合并到新的EntityManager中,然后尝试提交新的EntityManager.一个问题可能是需要重置已分配的任何ID,或者已分配或增加的乐观锁定版本.此外,如果原始EntityManager是EXTENDED,则正在使用的任何对象仍将分离,并且需要重置.

这个选项起初看起来很简单,直到我们不可避免地遇到那些预期的问题.某些服务可能由于各种原因触发刷新,这会增加@VersionDB(已回滚)和Java实体(不是)的字段.下一次"保存"调用merge,会引发意外情况OptimisticLockException.

有没有一种可靠的方法在Java实体bean中"回滚"版本字段?

好的,接缝很难.我们有自己的@Versions级联实体,因此手动执行它似乎很脆弱.(我们怎样才能可靠地知道原始(持久)版本?无法查询,因为其他一些用户可能会同时成功更新实体;查询当前版本可能会破坏oplock!)

错误处理的另一个更复杂的方法是始终使用非事务性EntityManager.在提交时,创建一个新的EntityManager,将非事务对象合并到其中,并提交新的EntityManager.如果提交失败,则只有新EntityManager的状态可能不一致,原始EntityManager将不受影响.这可以允许纠正问题,并且EntityManager重新合并到另一个新的EntityManager中.如果提交成功,则任何提交更改都可以合并回原始的EntityManager,然后可以继续正常使用.此解决方案需要相当大的开销,因此只应在真正需要错误处理时使用,并且JPA提供程序不提供任何替代方案.

这看似合乎逻辑. 有没有人有任何使用两个EntityManage(特别是Spring)实现这种恢复的经验?在尝试之前我应该​​注意哪些陷阱? 似乎每个服务和DAO现在都必须意识到这两个实体管理器(使用Spring,今天它们几乎是持久层不可知的).DAO'发现'操作使用一个EM; 'update'使用另一个.或者有单独的"读"和"写"DAO.哎哟.

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

  • 在UI中使用DTO,因此自动递增不会影响任何内容.丑陋.
  • 将呼叫移至任何组合操作merge结尾.只有在所有验证和状态更新成功后才会附加实体.似乎奇怪的是"保存"服务将不再merge(仅验证).实际上,UI将负责调用DAO!听起来这是不寻常的吗?

建议吗? 谢谢 :-)

更新 我的架构包括:

  • 由UI(JSF)更新的分离实体
  • 实体ID不是自动生成的(预先分配的UUID和/或业务键)
  • 实体具有@Version用于锁定的自动递增字段
  • "保存"服务验证,调用em.merge(JPA over Hibernate)
  • "进程"服务验证,应用业务逻辑,更新实体状态
  • 服务可以组成.一个UI按钮可能会
    1. (@Transactional关于UI控制器的Spring 建议:开始)
    2. 保存
    3. 过程1
    4. 过程2
    5. (@Transactional:提交)
  • 任何服务都可能抛出验证异常(JSR 303),它会按预期回滚(消息显示在UI中)

java merge hibernate jpa rollback

7
推荐指数
1
解决办法
4618
查看次数

标签 统计

hibernate ×1

java ×1

jpa ×1

merge ×1

rollback ×1