Hibernate 批量插入是如何工作的?

Posted

技术标签:

【中文标题】Hibernate 批量插入是如何工作的?【英文标题】:How Hibernate Batch insert works? 【发布时间】:2018-01-22 01:26:21 【问题描述】:

谁能解释一下

hibernate.jdbc.batch_size=1000 

if (i % 100 == 0 && i>0) 
                    session.flush();
                    session.clear();
                

一起工作? ...

【问题讨论】:

docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html @soorapadman,感谢您的文章.. 但是如果 hibernate.jdbc.batch_size 与我的刷新循环不同怎么办? 【参考方案1】:

Hibernate 属性 hibernate.jdbc.batch_size 是 hibernate 优化插入或更新语句的一种方式,而刷新循环是关于内存耗尽的。

当您尝试保存实体 hibernate fire 1 insert 语句时没有批量大小,因此如果您使用大集合,则对于每个 save hibernate fire 1 语句

想象一下下面这段代码:

for(Entity e : entities)
session.save(e);

这里 hibernate 将在您的集合中为每个实体触发 1 个插入语句。如果您的集合中有 100 个元素,那么将触发 100 个插入语句。 这种方法效率不高主要有两个原因:

1) 您的一级缓存呈指数级增长,您可能很快就会收到OutOfMemoryException。 2) 由于每个语句的网络往返,您会降低性能。

hibernate.jdbc.batch_size 和刷新循环有 2 个不同的目的,但是是互补的。

Hibernate 使用第一个来控制批处理的实体数量。在 Hibernate 中使用 java.sql.Statement.addBatch(...)executeBatch() 方法。

所以 hibernate.jdbc.batch_size 告诉 hibernate 在调用 executeBatch() 之前它必须调用多少次 addBatch()

所以设置这个属性并不会阻止你的内存耗尽。

为了处理内存,您必须定期刷新会话,这就是刷新循环的目的。

当你写的时候:

for(Entity e : entities)
if (i % 100 == 0 && i>0) 
                    session.flush();
                    session.clear();
                

您是在告诉 hibernate 每 100 个实体刷新和清除会话(释放内存)。

那么现在两者之间的联系是什么?

为了达到最佳效果,您必须定义您的 jdbc.batch_size 和您的刷新参数相同。

如果您定义的刷新参数低于您选择的 batch_size,那么休眠将更频繁地刷新会话,因此它将创建小批量,直到达到 btach 大小 效率不高

当 2 个相同时,如果集合的大小不是 batch_size 的倍数,则休眠将只执行最佳大小的批次,最后一个除外。

您可以查看以下post 了解有关最后一点的更多详细信息

【讨论】:

id生成策略限制等其他需求呢? by 和你的冲洗参数相同这是否意味着我必须每 50 次坚持做session.flush()?我可以等到整个过程结束后再做flush()吗?【参考方案2】:

hibernate.jdbc.batch_size 确定要执行的最大批处理大小。如果在达到指定的批大小(the same table 的挂起插入或更新语句的数量)之前执行了隐式或显式刷新,则所有挂起的语句都打包在一个批次中,并重新开始“累积”语句。

因此,在您的示例中,您将执行包含 100 条语句的批处理。或者,例如,如果批处理大小为 100 且模除数为 500,则当刷新操作发生时,您将执行 5 个批处理,每个批处理包含 100 个语句。

【讨论】:

【参考方案3】:

批处理允许您将相关的 SQL 语句分组到一个批处理中,并通过一次调用数据库来提交它们。

我们为什么需要

请记住,添加到 Statement 或 PreparedStatement 的每个更新都是由数据库单独执行的,这一点很重要。这意味着,其中一些可能会在其中一个失败之前成功。所有成功的语句现在都应用于数据库,但其余的更新可能不会。这可能会导致数据库中的数据不一致。

为避免这种情况,您可以在事务中执行批量更新。在事务中执行时,您可以确保执行所有更新,或者不执行任何更新。任何成功的更新都可以回滚,以防其中一个更新失败。

什么是批处理和刷新

批量大小和冲洗是不同的事情。当您将hibernate.jdbc.batch_size 设置为1000 时,这意味着hibernate 将批量插入或更新到1000 实体。flush 操作可用于在事务提交之前将所有更改写入数据库

如果您的批处理大小设置为 1000,并且您每 100 个实体刷新一次,Hibernate 将执行 10 次小批量的 100 个插入或更新语句。

请在此链接下方阅读更多内容:

http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html

Why number of objects being flushed should be equal to hibernate.jdbc.batch_size?

【讨论】:

以上是关于Hibernate 批量插入是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

HIbernate 批量插入或更新在 Spring Boot 中不起作用

如何在 MySQL 上使用 Hibernate 批量插入递增的 ID?

JPA/Hibernate 批量(批量)插入

为啥批量插入/更新更快?批量更新如何工作?

hibernate nativesqlquery批量插入

Hibernate/MySQL 批量插入问题