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

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查询,因为我认为级联插入会产生更干净的代码。

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

最佳答案

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

首先,有几点观察:

  • 从客户端传递到服务器的数据量与一个或多个插入语句相同,其中“数据量”表示您要存储的实际值。
  • Hibernate支持批量请求,因此客户端和服务器之间的往返次数可以与一个或多个插入语句大致相同。

  • 在幕后,Hibernate对其代表您执行的每个查询都使用PreparedStatement,并将其缓存和重用。 MySQL会缓存“编译” SQL语句。在不陷入细节的情况下,对基础技术进行了高度优化,可以多次运行相对少量的查询。

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

    由于许多原因,您必须在SQL中使用绑定(bind)变量,Hibernate会自动为您执行此操作。如果您执行一些自定义查询来测试一次插入式方法,则绝对也应该使用绑定(bind)变量。

    另一个注意事项是如何生成标识符。如果它是通过数据库中的标识列,则Hibernate需要为每一列接收ID,这通常仅在创建一行时才可能。因此,出于效率考虑,最好使用基于序列的标识符生成器,​​并在客户端缓存序列值。

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

    07-28 00:59
    查看更多