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 中不起作用