使用实体管理器进行异常处理

时间:2014-12-15 12:19:51

标签: jpa entitymanager

我听说在使用实体管理器提交事务时,如果提交失败,最好再次尝试,因为这可能是在事务处理过程中更改对象的问题。

这看起来像是一次正确的重试吗?

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++;
}

2 个答案:

答案 0 :(得分:0)

当你正在缓存&#34;异常&#34;在您的catch块中,您正在重新尝试更新无法完成更新的情况。例如,如果在数据库中找不到实体,那么您试图找到它两次。

你应该捕获最具体的异常&#34; OptimisticLockException&#34;。当实体的版本与存储在数据库中的版本不匹配时,抛出此异常。实体中的Version字段是实现此锁定策略的必要条件。

在高并发应用程序中还有其他锁定策略,但大多数时候乐观锁定策略是最合适的。

作为一个小细节,使用常数作为重试次数而不是&#34;魔术数字&#34;提高代码可读性,并且更容易修改将来的重试次数。

答案 1 :(得分:0)

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

  1. 用户1更改entityX并提交它。
  2. 用户2更改同一实体X的部分字段并尝试提交它。 EntityManager会抛出异常。
  3. 这里的正确方案是向用户表明异常,以便他重新读取实体并再次尝试相同的修改。

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