Jpa 使用实体管理器处理异常

Jpa 使用实体管理器处理异常,jpa,entitymanager,Jpa,Entitymanager,我听说在使用实体管理器提交事务时,如果提交失败,最好再试一次,因为在事务处理过程中对象可能会发生更改 这看起来像是一个正确的重试实现吗 int loopCount = 1; boolean transactionCommited = false; while(!transactionCommited && loopCount <3) { EntityManager em = EMF.getInstance().getEntityManager(); try

我听说在使用实体管理器提交事务时,如果提交失败,最好再试一次,因为在事务处理过程中对象可能会发生更改

这看起来像是一个正确的重试实现吗

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++;
}
int loopCount=1;
布尔TransactionCommitted=false;
当(!TransactionCommitted&&loopCount在catch块中缓存“Exception”时,在无法完成更新的情况下,您正在重试更新。例如,如果在数据库中找不到实体,您将尝试查找它两次

您应该捕获最具体的异常“OptimisticLockException”。当实体的版本与数据库中存储的版本不匹配时,会引发此异常。实体中的版本字段是实现此锁定策略的必要条件

在高并发应用程序中还可以使用其他锁定策略,但大多数情况下,乐观锁定策略是最合适的


作为一个小细节,使用常量作为重试次数,而不是“幻数”提高了代码的可读性,并且以后更容易修改重试次数。

通常,再次提交相同的更改是一个坏主意。即使引发的异常是
OptimisticLockException
,这也不是一个好主意,因为这可能意味着某人正在覆盖某人所做的更改。想象一下以下场景:

  • 用户1更改entityX并提交它
  • 用户2更改同一entityX的a部分字段并尝试提交它。
    EntityManager
    引发异常
  • 正确的场景是在这里向用户指示异常,以便他重新读取实体并重试相同的修改

    现在最重要的论点是为什么这是危险的:
    至少Hibernate知道,如果在抛出异常后尝试重用
    EntityManager
    ,可能会发生不好的事情。在数据损坏或应用程序停止正常工作之前,请查看或。

    在循环中,正如您所建议的,我正在通过调用Player playerToEdit=em.find(Player.class,id)进行读取;正确?是的,您正在重新读取。但是用户2没有看到这些更改(来自用户1),因此它只会覆盖user1!的更改。那么,在处理EntityManager时,我应该捕获什么类型的异常,以确保捕获到任何与jpa/持久性相关的内容?@AndreiI请您看看这个问题?如果用户2在ser 1完成了他们的提交,对吗?