【问题标题】:JPA eager fetching and pagination best practicesJPA 急切获取和分页最佳实践
【发布时间】:2019-05-03 08:08:59
【问题描述】:

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

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

但是当涉及到将它们结合起来时 - 如何以高效和干净的方式做到这一点变得不清楚。

  • 要么是 Eager fetch 有效,要么是在内存中应用分页(又名 HHH000104:firstResult/maxResults 使用集合提取指定;在内存中应用!

  • 要么是分页起作用,要么是急切地提取不起作用(即使resultSet 实际上包含相关实体),这会导致对数据库的额外查询以获取批次中每一行的相关实体。


最接近的,实际有效的是 https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/

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

问题:关于如何使用分页来急切获取相关实体,还有其他最佳实践吗?

注意:解决方案还应提供一种对从数据库检索的数据应用过滤器的方法。 (例如 JPQL WHERE 子句

【问题讨论】:

  • 一个简单的解决方案是只获取一页 ID(应用最大结果),然后查询所有实体,包括使用连接获取的连接实体,这些实体具有在第一个查询。

标签: jpa pagination jpql eager


【解决方案1】:

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

  1. 应用 where 条件和 pagination 的第一个查询。查询只返回 ids
  2. 第二个查询使用第一个查询返回的 id 并在相关实体上创建 FETCHs。

例如,第一个查询:

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();

如果您需要某个列排序,请注意。 order by 子句需要出现在这两个查询中,因为数据库不遵守您在数据库返回行时通过参数传递的 id 顺序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    • 2011-10-28
    • 1970-01-01
    相关资源
    最近更新 更多