繁体   English   中英

提交休眠事务有多昂贵?

[英]How expensive is committing a hibernate transaction?

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

在这种用例中,我必须为尚未创建的实体做好准备,因此我要求创建该实体(精确地说,具有唯一属性的模板),然后我改变它。 我的困境如下:一方面,我有两个明显不同的块,并且应该在适当的地方使用不同的catch子句,但最终情况是查询时实体不在那儿,但是当我尝试时又有一个毫秒创建它(因此ConstraintViolationException)是不应该经常发生的事情,因此要插入它是因为中间的一个额外的commit / beginTransaction似乎很累。

我主要关注的是会话同步和JDBC连接在提交/开始发生时带来的额外性能损失。
我错了吗? 我在寻找我不应该去的优化吗? 我想念什么吗?
提前致谢

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

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

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

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

休眠事务几乎只是数据库事务的包装。 因此,这与数据库事务一样昂贵。

通常,与优化一样,通常最好有清晰而安全的代码,而不是试图获得额外1%的性能。 但是我不知道您的用例。 如果以上每秒被调用几次,则不必担心性能。 如果每秒被调用数百次,则可能是一个问题。

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

在上述情况下,我将执行以下操作

  • 在代码中放置一会儿循环(全部,包括会话的打开/关闭)
  • 如果它命中了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();  
    }
}

我认为我实际上已经找到了用例的特定问题,那就是仅在实际需要时才打开事务,因此我节省了过早的性能难题:

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

这将使我能够定位每笔交易中的特定风险,并避免在不需要时提交和打开交易。 感谢您的意见。

无论您要做什么,写操作都不能在事务外部完成,如果没有正在进行的事务,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. 同步代码( 如果您在单个JVM中运行,则这只是一个选择)
  2. 锁定整个桌子(哎呀!)〜或〜
  3. 处理它并实现某种重试机制。

就个人而言,我会选择选项3。在性能方面,这是最好的选择,实际上这是一种常见的模式,尤其是在处理消息传递和高并发性时。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM