代码之家  ›  专栏  ›  技术社区  ›  Ittai

提交一个hibernate事务有多贵?

  •  1
  • Ittai  · 技术社区  · 16 年前

    在以下用例中,我通过JMS接收关于实体的消息,通过实体的唯一属性(不是PK),它要求我更新实体的状态:

    HibernateUtil.beginSession();  
    HibernateUtil.beginTransaction();  
    try{  
      Entity entity = dao.getEntityByUniqueProperty(propertyValue);  
      if (entity==null){  
        entity = dao.addEntityByUniqueProperty(propertyValue)  
      }  
      entity.setSomeProperty(otherPropertyValue);
      HibernateUtil.commitTransaction();
    } catch (ConstraintViolationException e){  
      HibernateUtil.rollbackTransaction();  
      //Do other things additionally  
    } catch (StaleStateObjectException e){  
      HibernateUtil.rollbackTransaction();  
      //Do other things additionally  
    } finally {  
      HibernateUtil.closeSession();  
    }
    

    在这个用例中,我必须准备好我试图更新的实体还没有被创建,所以我请求创建这样的实体(确切地说是一个模板,带有惟一属性),然后我更改它。 我的难题如下:

    我主要关心的是会话同步和JDBC连接在commit/begin发生时对性能的额外影响。

    提前谢谢

    4 回复  |  直到 16 年前
        1
  •  3
  •   Aaron Digulla    16 年前

    • 线程1创建了唯一实例
    • 线程2设置其他属性
    • 线程1设置其他属性

    问题:在这种情况下,DB是否一致?在类似的情况下会(不)一致吗?

    始终使用事务。DBs为此进行了优化。如果你有问题,就开始考虑你的设计。比如你每秒要处理成千上万条信息

        2
  •  2
  •   Mike Q    16 年前

    hibernate事务几乎只是DB事务的包装器。所以它和DB事务一样昂贵。

    如果您有一个性能问题,那么测量/计时/分析代码,直到您发现问题为止。通常你可以假设问题在一个地方,而实际上问题在另一个地方。

    在你上面的情况下,我会做以下事情

    • 如果它击中 ConstraintViolationException 块日志和 continue
    • 那就行了 break

    编辑:我将如何做到这一点。。。。

    // loop as it is possible we get a retryable exception, see below
    while (true){
        HibernateUtil.beginSession();
        HibernateUtil.beginTransaction();  
        try{  
          Entity entity = dao.getEntityByUniqueProperty(propertyValue);  
          if (entity==null){  
            entity = dao.addEntityByUniqueProperty(propertyValue)  
          }  
          entity.setSomeProperty(otherPropertyValue);
          HibernateUtil.commitTransaction();
    
          // success
          break;
    
        } catch (ConstraintViolationException e){  
          HibernateUtil.rollbackTransaction();
    
          // this is ok, another txn must have added the entity at the same time
          // try again and it will find the entity this time
          continue;
    
        } catch (StaleStateObjectException e){  
          HibernateUtil.rollbackTransaction();  
          //Do other things additionally  
    
        } finally {  
          HibernateUtil.closeSession();  
        }
    }
    
        3
  •  1
  •   Pascal Thivent    16 年前

    不管您要做什么,写操作都不能在事务之外完成,如果没有正在进行的事务,Hibernate会抱怨并抛出异常。所以别无选择。

    现在,您的用例-a findOrCreate() -不是一件小事。正如您所提到的,您可能会面临一个竞赛条件:

    T1: BEGIN TX;
    
    T2: BEGIN TX;
    
    T1: getEntityByUniqueProperty("foo"); //returns null
    
    T1: getEntityByUniqueProperty("foo"); //returns null
    
    T1: addEntityByUniqueProperty("foo");
    T1: COMMIT; //row inserted
    
    T1: addEntityByUniqueProperty("foo");
    T2: COMMIT; //constraint violation
    

    所以你要么

    1. 同步代码(这只是一个选项 您正在单个JVM中运行)~或者~
    2. 处理它并实现某种重试机制。

    就我个人而言,我会选择第三种选择。就性能而言,它是最好的选择,因为它实际上是一种常见的模式,特别是在处理消息传递和高并发性时。

        4
  •  1
  •   Dinei Ahmad Yones    11 年前

    我想我已经找到了我的用例的具体问题,那就是只在实际需要的时候打开事务,所以我省去了过早的性能难题:

    try {
        HibernateUtil.beginSession();
        Entity entity = dao.getEntityByUniqueProperty(propertyValue);
        if (entity==null){
            HibernateUtil.beginTransaction();
            try {
                entity = dao.addEntityByUniqueProperty(propertyValue)
                HibernateUtil.commitTransaction();
            } catch (ConstraintViolationException e){
                HibernateUtil.rollbackTransaction();
                HibernateUtil.closeSession();
                HibernateUtil.beginSession();
                entity = dao.getEntityByUniqueProperty(propertyValue);
                //Do other things additionally
            }
        }
        entity.setSomeProperty(otherPropertyValue);
        HibernateUtil.commitTransaction();
    } catch (StaleStateObjectException e){
        HibernateUtil.rollbackTransaction();
        //Do other things additionally
    } finally {
        HibernateUtil.closeSession();
    }
    

    谢谢你的评论。