JPA 急切获取和分页最佳实践

Dmi*_*tov 9 pagination jpa eager jpql

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

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

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

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

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


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

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

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

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

Dhe*_*rik 8

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

  1. 第一个应用where条件和分页的查询。查询仅返回 ID
  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();
Run Code Online (Sandbox Code Playgroud)

第二个查询:

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();
Run Code Online (Sandbox Code Playgroud)

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