我想在交易失败后恢复.
现在,当然,在任何回滚之后,所有实体都将分离,实体管理器将关闭.但是,UI仍然保留分离的实体.显然我们不能丢弃用户的更改,所以我们想让他们重试(修复突出显示的验证错误,然后再次单击按钮).
一种错误处理方法是在提交失败后调用每个托管对象的合并到新的EntityManager中,然后尝试提交新的EntityManager.一个问题可能是需要重置已分配的任何ID,或者已分配或增加的乐观锁定版本.此外,如果原始EntityManager是EXTENDED,则正在使用的任何对象仍将分离,并且需要重置.
这个选项起初看起来很简单,直到我们不可避免地遇到那些预期的问题.某些服务可能由于各种原因触发刷新,这会增加@Version
DB(已回滚)和Java实体(不是)的字段.下一次"保存"调用merge
,会引发意外情况OptimisticLockException
.
有没有一种可靠的方法在Java实体bean中"回滚"版本字段?
好的,接缝很难.我们有自己的@Versions级联实体,因此手动执行它似乎很脆弱.(我们怎样才能可靠地知道原始(持久)版本?无法查询,因为其他一些用户可能会同时成功更新实体;查询当前版本可能会破坏oplock!)
错误处理的另一个更复杂的方法是始终使用非事务性EntityManager.在提交时,创建一个新的EntityManager,将非事务对象合并到其中,并提交新的EntityManager.如果提交失败,则只有新EntityManager的状态可能不一致,原始EntityManager将不受影响.这可以允许纠正问题,并且EntityManager重新合并到另一个新的EntityManager中.如果提交成功,则任何提交更改都可以合并回原始的EntityManager,然后可以继续正常使用.此解决方案需要相当大的开销,因此只应在真正需要错误处理时使用,并且JPA提供程序不提供任何替代方案.
这看似合乎逻辑. 有没有人有任何使用两个EntityManage(特别是Spring)实现这种恢复的经验?在尝试之前我应该注意哪些陷阱? 似乎每个服务和DAO现在都必须意识到这两个实体管理器(使用Spring,今天它们几乎是持久层不可知的).DAO'发现'操作使用一个EM; 'update'使用另一个.或者有单独的"读"和"写"DAO.哎哟.
我考虑过的其他选择包括:
merge
的结尾.只有在所有验证和状态更新成功后才会附加实体.似乎奇怪的是"保存"服务将不再merge
(仅验证).实际上,UI将负责调用DAO!听起来这是不寻常的吗?建议吗? 谢谢 :-)
更新 我的架构包括:
@Version
用于锁定的自动递增字段em.merge
(JPA over Hibernate)@Transactional
关于UI控制器的Spring 建议:开始)@Transactional
:提交)