我遇到的一个问题是如何在EJB层引发Web层(.war代码)时捕获OptimisticLockException。
我们正在使用JEE5,GlassFishV2.1和JPA(带有TopLinks)和容器管理事务。但是当由于同一实体上的另一个并发用户的trnasaction而发生脏读时。它在war层给出了Transaction.RollBackException。实际上是由OptimisticLockException引起的。但我无法在战争端捕获OptimisticLockException。
在ejb方面使用em.flush然后我们可以捕获并向战争抛出一些自定义异常。 但我认为em.flush会刷新所有数据库,这是否是一项昂贵的操作?
try{
//some enitity
em.flush()
}
catch(OptimisticLockException ole){
throw ole;
}
我的意见是不要调用em.flush,因为90%的情况下不存在OptimisticLockException并且在.war中捕获EJBException然后重试它。有更好的选择吗?
尝试{ //一些代码 } catch(EJBException ex){
if (ex.getCausedByException().getCause().toString().
indexOf("javax.transaction.RollbackException")!= -1){
// do work
}
}
}
答案 0 :(得分:1)
你可以做任何一件事。 flush()在技术上并不是一项昂贵的操作,因为它在写入数据库时所做的工作不再需要通过提交来完成,因此没有额外的数据库访问,也没有“刷新所有数据库”。 flush()确实有一些开销,更改将计算两次,一次用于刷新,一次用于提交,一次用于提交。根据您的更改策略和托管对象的数量,这确实有成本。 Flush还需要将托管对象重新置于跟踪的托管状态,这也需要一些成本,但与数据库访问成本相比通常较小。
请注意,在提交期间可能会发生其他错误而不是锁定错误,因此即使您使用刷新来捕获锁定错误,您仍然需要在战争中使用代码来处理其他失败原因,因此不使用flush,只是让一般事务失败错误处理可能是最好的解决方案。如果你想为锁定错误做一些特别的事情,你应该能够在原因中找到异常链,但是在重试操作时要小心,你是因为某个原因而锁定的,所以应该把错误报告给用户让他们重试他们的操作。