问题描述
我正在使用CriteriaQuery和TypedQuery为我的一张表使用服务器端分页,并设置以下值: typedQuery.setFirstResult(0); typedQuery.setMaxResults(100);
不幸的是,在Oracle DB上执行的生成的SQL查询中,我从没有看到ROWNUM条件。我还在TypedQuery中添加了ORDER BY,但是查询仍然进行了一个简单的选择,而没有限制数据库的结果。
结果是我收到以下警告 HHH000104:用集合访存指定的firstResult / maxResults;在内存中应用!。换句话说,Hibernate在内存上进行分页,因为它不在数据库上执行。对于此警告,我阅读了以下文章https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/,但在将我的查询分为两个查询(获取ID,然后获取这些ID的数据)之前,我想到了给setMaxResults。我仍然想知道为什么生成的查询不符合ROWNUM的要求。
远程信息:
- 数据库:Oracle 18
- 对话框:org.hibernate.dialect.Oracle12cDialect
- 休眠:5.3.15
- JDK:11
解决方法
加入数据时,父项将被重复n次。例如:
select p from Post p join p.comments
如果一个帖子下有20条评论,则此帖子将被20次发送20次不同评论。 在这种情况下限制行没有意义,因为返回的帖子的实际数量将不等于页面大小。换句话说,将页面限制为20条记录只会返回一篇帖子。
,您必须了解,如果选择一个实体,则第一个/最大结果适用于实体级别。如果获取联接集合属性或对集合属性使用实体图,则可以更改JDBC为每个实体返回的行的基数,即,每个集合元素都将复制主实体行的每一行。这样做的结果是,Hibernate不再可以使用ROWNUM进行分页,这就是为什么您在查询中看不到它的原因。如果删除提取联接,则会看到ROWNUM的使用。
话虽如此,这是Blaze-Persistence的完美用例。
Blaze-Persistence是JPA之上的查询构建器,它支持JPA模型之上的许多高级DBMS功能。随附的分页支持可解决您可能遇到的所有问题。
它还具有Spring Data集成,因此您可以像现在一样使用相同的代码,只需添加依赖项并进行设置:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-setup
Blaze-Persistence具有许多可以配置的分页策略。默认策略是将ID查询内联到主查询中。像这样:
select u
from User u
left join fetch u.notes
where u.id IN (
select u2.id
from User u2
order by ...
limit ...
)
order by ...