JPA急加载和分页的最佳实践

10

经过一些研究,我发现了很多关于如何编写简单高效的代码(使用JPQL)的资料,可以实现以下功能:

  1. 允许获取相关实体信息(例如使用JOIN FETCH)
  2. 允许对单个实体进行分页

但是,当需要将它们结合起来时,如何以高效且清晰的方式实现就变得不太清楚了。

  • 要么是能够正常获取相关实体信息,但在内存中应用分页(也就是说,"HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!")

  • 要么是能够正常分页,但无法获取相关实体信息(即使resultSet实际上包含相关实体),导致每个批次中的每行都需要向数据库发出额外的查询以获取相关实体。


最接近实际工作的解决方案是https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/

但这让我想知道是否有更直观、更简洁的解决方案?

问题:是否还有其他最佳实践可以在获取相关实体信息的情况下使用分页?

注意:解决方案还应提供一种从数据库中检索数据并应用筛选器的方法(例如JPQL WHERE clause


2
一个简单的解决方案就是获取一组 ID(应用最大结果限制),然后使用联接抓取查询所有实体,包括使用联接抓取连接的实体,这些实体在第一个查询中检索到其中一个 ID。 - JB Nizet
1个回答

10

解决此问题的最简单方法是使用两个查询:

  1. 第一个查询应用where条件和pagination。此查询仅返回ID。
  2. 第二个查询使用在第一个查询中返回的ID,并在相关实体上执行FETCH

例如,第一个查询:

String jpql = "SELECT user.id FROM User user WHERE user.name = 'John'"

Query q = em.createQuery(jpql); 
q.setFirstResult(0);
q.setMaxResults(10);

List<Long> ids = q.getResultList();

第二个查询:

String jqpl = "SELECT user FROM User user JOIN FETCH user.address WHERE user.id IN (:ids)"
Query q = em.createQuery(jpql); 
q.setParameter("ids", ids);

List<User> users = q.getResultList();

如果您需要按某个列进行排序,请注意。由于数据库返回行时不遵守传递的参数中的id顺序,因此这两个查询需要在其中添加order by子句。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接