【问题标题】:Is Session.Save sending a request to the database?Session.Save 是否向数据库发送请求?
【发布时间】:2019-01-08 10:24:02
【问题描述】:

我必须改进一个非常慢的代码的性能,而且我对 Hibernate 还是很陌生。我仔细研究了代码并得出结论,问题在于它有大量要加载的实体和update/insert。要将算法转换为更易于理解的示例,假设我们有一个这样的算法:

for each competitionToSave in competitionsToSave
    competition <- load a Competition by competitionToSave from database

    winner <- load Person by competitionToSave.personID

    do some preprocessing

    if (newCompetition) then
        insert competition
    else
        update competition
    end if
end for

competitionToSave 中有很多competitions 时,这个算法当然是有问题的。所以,我的计划是选择所有涉及两个数据库请求最多的competitions 和winners,预处理数据,这将加快读取速度,但更重要的是,确保我将通过insert/@ 保存987654331@ 批次 100 competitions 而不是单独保存。由于我对 Hibernate 很陌生,所以我咨询了documentation 并找到了以下示例:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

但是,我不确定我是否理解正确。关于方法.save()我看了:

持久化给定的瞬态实例,首先分配一个生成的 标识符。 (或者使用标识符属性的当前值,如果 使用分配的生成器。)此操作级联到关联 如果关联使用 cascade="save-update" 映射,则实例。

但我不清楚是否每个save 都会向数据库发送请求。如果我假设在取自文档session.save(customer) 的示例中将对象的修改保存在Session 而不 向数据库发送请求然后在每20 个项目上@ 987654337@向数据库发送请求,session.clear()删除Session的缓存?

【问题讨论】:

  • 据我所知hibernate,你的想法是对的。我刚刚从事一个项目,必须保存/更新 250 万条记录。这个项目告诉我hibernate对大量数据使用废话。最后,我使用了一个只有 1 事务的存储过程。如果您真的想加快休眠速度,请研究批处理以及适当的事务管理
  • @XtremeBaumer 出色的评论。阅读文档时,我考虑过这种可能性,但在我的具体情况下,这似乎是一种矫枉过正。客户每天等待 10 分钟。我估计我想要生成的理想代码大约快 200 倍,这意味着我们将有 600 000 / 200 毫秒,也就是 3 秒。这是可以接受的。

标签: java hibernate batch-updates batch-insert


【解决方案1】:

您的假设是正确的,尽管插入将被逐个触发:

insert into Customer(id , name) values (1, 'na1');
insert into Customer(id , name) values (2, 'na2');
insert into Customer(id , name) values (3, 'na3'); 

您可以尝试利用批量插入功能来进一步提高性能。

有一个hibernate属性你可以定义为hibernate的SessionFactory的属性之一:

<property name="jdbc.batch_size">20</property>

使用此批处理设置,您应该在每次刷新后都有这样的输出:

insert into Customer(id , name) values (1, 'na1') , (2, 'na2') ,(3, 'na3')..

一个插入而不是二十个。

【讨论】:

  • 优秀的答案。不过,我想仅为此方法设置批量大小。这是难题中唯一缺少的部分,这使我无法接受您的答案,但会尝试找出答案。如果我找到它,我会在这里评论它。 jdbc.batch_size 的值(在您的示例中为 20)意味着不会执行任何插入,直到调用刷新或“插入队列”的大小达到 20,如果我没记错的话。
  • 我从这里发现:stackoverflow.com/questions/2729255/… 我需要创建另一个会话工厂才能做到这一点。如果您将此信息添加到您的高质量答案中,那么我会接受它。
  • 这是一个补充,在原始问题中并未真正指出为问题。在我看来,这是一个单独的问题。
  • 更改项目中广泛使用的 SessionFactory 的批量大小可能会产生不良副作用。我认为我们需要让已接受答案的未来读者知道他们如何避免这种不良副作用。
  • 定义该属性的副作用和陷阱超出了范围,特别是如果您的标题和问题只是为了确认您对休眠saveflush 操作的理解。如果读者只是阅读有关该主题的众多优秀文章中的一篇 -> vladmihalcea.com/… 并通过这种方式获得更广泛的理解,那就更好了。干杯
猜你喜欢
  • 2018-10-24
  • 2021-04-21
  • 2021-06-12
  • 2020-10-07
  • 2023-04-03
  • 2019-08-27
  • 2022-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多