我听说在使用实体管理器提交事务时,如果提交失败,最好再次尝试,因为这可能是在事务处理过程中更改对象的问题。
这看起来像是一次正确的重试吗?
int loopCount = 1;
boolean transactionCommited = false;
while(!transactionCommited && loopCount <3) {
EntityManager em = EMF.getInstance().getEntityManager();
try{
EntityTransaction tx = em.getTransaction();
tx.begin();
Player playerToEdit = em.find(Player.class, id);
playerToEdit.setLastName(lastName);
tx.commit();
transactionCommitted = true;
} catch(Exception e){
if(loopCount == 2){
//throw an exception, retry already occurred?
}
} finally{
if(tx.isActive()){
tx.rollback();
}
em.close();
}
loopCount++;
}
答案 0 :(得分:0)
当你正在缓存&#34;异常&#34;在您的catch块中,您正在重新尝试更新无法完成更新的情况。例如,如果在数据库中找不到实体,那么您试图找到它两次。
你应该捕获最具体的异常&#34; OptimisticLockException&#34;。当实体的版本与存储在数据库中的版本不匹配时,抛出此异常。实体中的Version字段是实现此锁定策略的必要条件。
在高并发应用程序中还有其他锁定策略,但大多数时候乐观锁定策略是最合适的。
作为一个小细节,使用常数作为重试次数而不是&#34;魔术数字&#34;提高代码可读性,并且更容易修改将来的重试次数。
答案 1 :(得分:0)
通常,再次尝试提交相同的更改是个坏主意。即使抛出的异常是OptimisticLockException
,这也不是一个好主意,因为这可能意味着某人正在覆盖某人所做的更改。想象一下以下场景:
EntityManager
会抛出异常。这里的正确方案是向用户表明异常,以便他重新读取实体并再次尝试相同的修改。
现在最重要的论点是为什么这是危险的:
至少Hibernate是众所周知的,如果你在抛出异常后尝试重用EntityManager
,可能会发生BAD事情。在数据损坏或您的应用程序停止工作之前,请查看this article或this one。