在JPA中插入多行的最有效方法

时间:2015-11-30 20:45:43

标签: java mysql hibernate jpa-2.0

我有父/子单向关系。当我检查日志时,我看到每个子行都有一个单独的插入查询,相当于让我们说:

insert into childTable(col1, col2) values(val1, val2);
insert into childTable(col1, col2) values(val3, val4);

在单个查询中插入所有行不是更有效吗?有点像:

insert into childTable(col1, col2) values(val1, val2), (val3, val4)

有没有办法强制JPA生成多行插入而不是单行插入?

编辑: 我目前正在使用级联插入,因此我插入了父级,并自动生成子级的插入内容。我宁愿继续使用该方法,而不是让我们说手动创建一个巨大的SQL查询,因为我认为级联插入产生更清晰的代码。

我已经定期刷新会话以控制L1缓存的大小,因此耗尽内存不是问题。

1 个答案:

答案 0 :(得分:3)

在单个查询中插入所有行实际上效率较低。

首先,有几点意见:

  1. 从客户端传递到服务器的数据量与一个或多个insert语句相同,其中“data of data”表示您要存储的实际值。
  2. Hibernate支持批量处理请求,因此客户端和服务器之间的往返次数可以与一个或多个插入语句大致相同。
  3. 在幕后,Hibernate为您代表它执行的每个查询使用PreparedStatement,这些查询被缓存并重用。 MySQL缓存“编译”SQL语句。在没有陷入细节的情况下,底层技术经过高度优化,可以多次运行相对较少的查询。

    如果将insert作为单个语句执行,那么每次要插入的值的数量不同时,必须编译和缓存新的SQL(可能从缓存中推送另一个查询),这会增加开销。每次只使用相同的SQL时,可以避免这种开销。

    由于许多原因,您必须在SQL中使用绑定变量,Hibernate将自动为您执行此操作。如果你做一些自定义查询来测试一次性插入方法,你肯定也应该使用绑定变量。

    另一个考虑因素是如何生成标识符。如果它是通过数据库中的标识列,那么Hibernate需要接收每列的ID,这通常只有在创建一行时才可以。出于这个原因,基于序列的标识符生成器是效率的首选,客户端缓存序列值。

    我刚注意到你的编辑:我的经验是Hibernate在处理插入父子数据时会做“额外”更新。我设法通过将映射更改为具有“连接”表(就像您将看到的多对多关系)来获得“纯”插入,即使我只有多对一的关系。就我而言,在三个表中进行大量插入操作要快得多,而插入更少,并且更新到两个表中。如果你担心性能,你肯定应该计划一段时间来调整Hibernate配置。