java - JPA 实体图和分页

标签 java hibernate jpa pagination entitygraph

在我当前的项目中,我们在系统中有多个搜索页面,我们从数据库中获取大量数据以显示在 UI 的大型表格元素中。我们使用 JPA 进行数据访问(我们的提供程序是 Hibernate)。大多数页面的数据是从多个数据库表中收集的——在许多情况下大约有 10 个——包括一些来自 OneToMany 关系的聚合数据(例如“X 类型的关联实体的数量”)。为了提高性能,我们使用 TypedQuery.setFirstResult()TypedQuery.setMaxResults() 的结果集分页从数据库中延迟加载额外的行作为用户滚动表格。由于搜索非常动态,我们使用 JPA CriteriaQuery API 来构建查询。然而,我们目前有点受 N+1 SELECT 问题的困扰。实际上,在某些情况下这很糟糕,因为我们可能会遍历 3 个级别的嵌套 OneToMany 关系,其中每个级别的数据都是延迟加载的。我们不能真正将这些集合声明为实体映射中的预加载,因为我们只对某些页面中的它们感兴趣。 IE。我们可能会在多个不同页面中从同一个表中获取数据,但我们会在不同页面中显示来自该表和不同关联表的不同数据。

为了缓解这种情况,我们开始试验 JPA 实体图,它们似乎对解决 N+1 SELECT 问题有很大帮助。但是,当您使用实体图时,Hibernate 显然会在内存中应用分页。我多少能理解它为什么这样做,但在许多情况下,这种行为否定了实体图的很多(如果不是全部)好处。当我们不使用实体图时,我们可以在不应用任何 WHERE 限制的情况下加载数据(即将整个表视为结果集),无论表有多少百万行,因为只有非常有限的行被加载实际上是由于分页而获取的。现在分页是在内存中完成的,Hibernate 基本上是获取整个数据库表(加上实体图中定义的所有关系),然后在内存中应用分页,丢弃其余的行。不好。

所以问题是,是否有一种有效的方法来使用 JPA (Hibernate) 应用分页和实体图?如果 JPA 没有为此提供解决方案,那么 Hibernate 特定的扩展也是可以接受的.如果这也不可能,那么其​​他选择是什么?使用数据库 View ? View 会有点麻烦,因为我们支持多个数据库供应商。为不同的供应商创建所有必要的 View 会大大增加开发工作量。

我的另一个想法是像我们目前所做的那样同时应用实体图和分页,如果它们返回太多行,则根本不触发任何查询。我已经需要执行 COUNT 个查询以使延迟加载行在 UI 中正常工作。

最佳答案

我不确定我是否完全理解您的问题,但我们遇到了类似的事情:我们已经分页了可能包含来自多个联合实体的数据的实体列表。这些列表可能会被排序和过滤(由于 dbms 中缺少功能,因此必须在内存中应用其中一些排序/过滤器,但这只是旁注),然后应应用分页。

将所有数据保存在内存中效果不佳,因此我们采用了以下方法(可能有更好/更标准的方法):

  1. 使用查询加载主要实体的主键(在我们的例子中是简单的 longs)。仅加入排序和过滤所需的内容,使查询尽可能简单。

    在我们的例子中,查询实际上会加载更多数据以在必要时在内存中应用排序和过滤器,但该数据会尽快释放并且只保留主键。
  2. 在显示特定页面时,我们会提取页面的相应主键,并使用第二个查询来加载要在该页面上显示的所有内容。第二个查询可能包含更多连接,因此比第 1 步中的查询更复杂、更慢,但由于我们只加载该页面的数据,因此系统的实际负担很低。

关于java - JPA 实体图和分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34764696/

相关文章:

java - 迁移到 jboss wildfly

java - 如何在java中获取当前日期(仅日期格式)并将其保存在Notes文档中

java - libgdx如何将屏幕分成4部分

java - 是否可以设置Hibernate的 "default"变量名映射?

java - hibernate : "Session is closed"虽然从未关闭(手动)

java - 使用列表作为列会导致性能不佳 - JPA

java - Spring JPA中无法使用多线程从多个数据库中删除数据

java - 如何注释 Hibernate 实体以同时支持 Java 和数据模型?

java - 如何禁用 karaf-maven-plugin 4 严格依赖约束检查

java - JAX-RS Provider 的 Filter 方法永远不会被调用