提交hibernate事务有多贵?

时间:2010-08-30 14:44:42

标签: java performance hibernate transactions

我有一个以下用例,我通过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();  
}

在这个用例中,我必须为我正在尝试更新的实体尚未创建的事实做好准备,因此我要求创建这样的实体(它的模板与unique属性一样精确) )然后我改变它。 我的dillema如下: 一方面我有两个明显不同的块,我应该在适当的地方使用不同的catch子句但是当我查询时实体不存在的结束情况但是当我尝试创建它时是否有ms(因此ConstraintViolationException) )是不应该经常发生的东西,因为插入因为中间的额外提交/ beginTransaction看起来很腰。

我主要关注会话同步和JDBC连接的额外性能损失,这些都是在提交/开始发生时完成的。
我错了吗?我在找不到优化的地方吗?我错过了什么吗? 提前致谢

4 个答案:

答案 0 :(得分:3)

首先,您需要一个交易。没有它,上面的代码将无法工作,因为这可能发生:

  • 线程1创建了唯一实例
  • 线程2获取唯一实例
  • 线程2设置其他属性
  • 线程1设置其他属性
  • 线程1刷新缓存
  • 线程2刷新缓存

问题:在这种情况下数据库是否一致?在类似案件中是否(不)一致?

始终使用交易。数据库针对它进行了优化。如果您遇到问题,请开始考虑您的设计。就像每秒必须处理数千条消息一样,您的性能工具表明此代码已成为瓶颈。不要相信你的直觉。

答案 1 :(得分:2)

hibernate事务几乎只是数据库事务的包装器。因此,数据库交易会很昂贵。

与往常一样,优化通常最好是拥有清晰安全的代码,而不是试图获得额外的1%性能。但我不知道你的用例。如果上面几秒钟被调用,那么不要担心性能。如果它被称为每秒几百次,那么它可能是一个问题。

如果遇到性能问题,请测量/时间/配置代码,直到找到问题为止。通常,您可以假设问题出现在一个地方,而实际上是在其他地方。

在上述情况下,我会做以下

  • 在代码中放置一个while循环(所有这些,包括会话打开/关闭)
  • 如果它遇到ConstraintViolationException阻止日志和continue,那么为了编写一些额外的逻辑,只需再次尝试,它就会找到另一个事务添加并适当更新的新行。 / LI>
  • 它可以正常运行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();  
    }
}

答案 2 :(得分:1)

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

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();
}

这将使我能够本地化每个事务中的特定风险,并避免在不需要时提交和打开事务。 感谢您的评论。

答案 3 :(得分:1)

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

现在,您的用例 - 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. 同步代码(这只是一个选项 IF 你在一个JVM中运行)〜或〜
  2. 锁定整个桌子(哎哟!)〜或〜
  3. 处理它并实施某种重试机制。
  4. 就个人而言,我会选择选项3.性能方面,它是最好的选择,实际上是一种常见模式,尤其是在使用消息传递和高并发时。