JPA 急切抓取和分页最佳实践
JPA eager fetching and pagination best practices
经过一些研究,我发现了很多关于如何编写简单高效的代码(使用 JPQL)的资料:
- 允许预先获取相关实体(例如使用 JOIN FETCH)。
- 允许在单个实体上分页。
但是当涉及到将两者结合时 - 不清楚如何以高效和干净的方式做到这一点。
要么是预取有效,但正在内存中应用分页(a.k.a。HHH000104:firstResult/maxResults 指定集合获取;应用在记忆中!)
要么是分页有效,但急切获取无效(即使 resultSet
实际上包含相关实体),导致对数据库进行额外查询以获取相关实体一批中的每一行。
最接近实际有效的是
https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/
但这让我想知道是否有更直观、更干净的解决方案?
问题:关于如何使用分页来预获取相关实体,是否还有其他最佳实践?
注意:解决方案还应该提供一种方法来对从数据库检索的数据应用过滤器。 (例如 JPQL WHERE 子句)
解决此问题的最简单方法是使用两个查询:
- 应用 where 条件和 pagination 的第一个查询。查询 return 只有 ids
- 第二个查询使用第一个查询中的 ID returned 并在相关实体上创建
FETCH
s。
例如,第一个查询:
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
子句需要出现在这两个查询中,因为当数据库 return 行时,数据库不遵守您通过参数传递的 id
顺序。
经过一些研究,我发现了很多关于如何编写简单高效的代码(使用 JPQL)的资料:
- 允许预先获取相关实体(例如使用 JOIN FETCH)。
- 允许在单个实体上分页。
但是当涉及到将两者结合时 - 不清楚如何以高效和干净的方式做到这一点。
要么是预取有效,但正在内存中应用分页(a.k.a。HHH000104:firstResult/maxResults 指定集合获取;应用在记忆中!)
要么是分页有效,但急切获取无效(即使
resultSet
实际上包含相关实体),导致对数据库进行额外查询以获取相关实体一批中的每一行。
最接近实际有效的是 https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/
但这让我想知道是否有更直观、更干净的解决方案?
问题:关于如何使用分页来预获取相关实体,是否还有其他最佳实践?
注意:解决方案还应该提供一种方法来对从数据库检索的数据应用过滤器。 (例如 JPQL WHERE 子句)
解决此问题的最简单方法是使用两个查询:
- 应用 where 条件和 pagination 的第一个查询。查询 return 只有 ids
- 第二个查询使用第一个查询中的 ID returned 并在相关实体上创建
FETCH
s。
例如,第一个查询:
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
子句需要出现在这两个查询中,因为当数据库 return 行时,数据库不遵守您通过参数传递的 id
顺序。