Hibernate分页机制

我正在尝试使用Hibernate分页进行查询(PostgreSQL)

我为我的sql查询设置了setFirstResult(0),setMaxResults(20)。 我的代码如下:

Session session = getSessionFactory().getCurrentSession(); session.beginTransaction(); Query query = session.createQuery("FROM Customers"); query.setFirstResult(0); query.setMaxResults(20); List entities = query.list(); session.getTransaction().commit(); 

但是在查看SQL hibernate日志时,我仍然看到完整的SQL查询:

 Hibernate: select customer0_.id as id9_, customer0_.customer_name as dst2_9_, customer0_.addres as dst3_9_ from tbl_customers customer0_ 

为什么查询Hibernate分页SQL日志时没有LIMIT OFFSET?

有谁知道Hibernate分页机制?

我想Hibernate将选择所有数据,将数据放入Resultset,然后在Resultset中进行分页,对吧?

我在查询和hibernate回调中使用。 两者都按预期工作。 Hibernate Query在给定的First和Max大小之间执行结果。 这里好像你通过SQL而不是HQL来查询。 如果是的话它应该不起作用。

– 在这里查看我的代码。

  Query query = this.getSession().createQuery("FROM QueryType"); query.setFirstResult(0); query.setMaxResults(20); List toDelete = query.list(); 

并在日志中:

选择*来自(选择 – 所有列名称。(不想在这里分享。)来自MY_TBL_NAME querytype0_)其中rownum <=?

有很多方法可以分页。

HQL和setFirstResult,setMaxResults API

 Session session = sessionFactory.openSession(); Query query = session.createQuery("From Foo"); query.setFirstResult(0); query.setMaxResults(10); List fooList = query.list(); //Total count String countQ = "Select count (f.id) from Foo f"; Query countQuery = session.createQuery(countQ); Long countResults = (Long) countQuery.uniqueResult(); //Last Page int pageSize = 10; int lastPageNumber = (int) ((countResult / pageSize) + 1); 

HQL和ScrollableResults API

 String hql = "FROM Foo f order by f.name"; Query query = session.createQuery(hql); int pageSize = 10; ScrollableResults resultScroll = query.scroll(ScrollMode.FORWARD_ONLY); resultScroll.first(); resultScroll.scroll(0); List fooPage = Lists.newArrayList(); int i = 0; while (pageSize > i++) { fooPage.add((Foo) resultScroll.get(0)); if (!resultScroll.next()) break; } //Total count resultScroll.last(); int totalResults = resultScroll.getRowNumber() + 1; 

只需Criteria API

 Criteria criteria = session.createCriteria(Foo.class); criteria.setFirstResult(0); criteria.setMaxResults(pageSize); List firstPage = criteria.list(); //Total count Criteria criteriaCount = session.createCriteria(Foo.class); criteriaCount.setProjection(Projections.rowCount()); Long count = (Long) criteriaCount.uniqueResult(); 

baeldung用例子列出了所有这些。

正如我在本文中解释的那样,您可以对实体查询和本机SQL使用JPA分页。

要限制基础查询ResultSet大小,JPA Query接口提供setMaxResults方法 。

导航以下页面需要将结果集定位在最后一页结束的位置。 为此,JPA Query接口提供了setFirstResult方法 。

JPQL

 List posts = entityManager .createQuery( "select p " + "from Post p " + "order by p.createdOn ") .setFirstResult(10) .setMaxResults(10) .getResultList(); 

DTO投影查询

JPA查询分页不仅限于仅返回实体的实体查询。 您也可以将它用于DTO投影。

 List summaries = entityManager .createQuery( "select new " + " com.vladmihalcea.book.hpjp.hibernate.fetching.PostCommentSummary( " + " p.id, p.title, c.review " + " ) " + "from PostComment c " + "join c.post p " + "order by c.createdOn") .setMaxResults(10) .getResultList(); 

本机SQL查询

JPA查询分页不仅限于实体查询,例如JPQL或Criteria API。 您也可以将它用于本机SQL查询。

 List posts = entityManager .createNativeQuery( "select p.id as id, p.title as title " + "from post p " + "order by p.created_on", Tuple.class) .setFirstResult(10) .setMaxResults(10) .getResultList(); 

加入FETCH和分页

但是,如果我们尝试在实体查询中使用JOIN FETCH子句,同时还使用JPA分页:

 List posts = entityManager.createQuery( "select p " + "from Post p " + "left join fetch p.comments " + "order by p.createdOn", Post.class) .setMaxResults(10) .getResultList(); 

Hibernate将发出以下警告消息:

 HHH000104: firstResult/maxResults specified with collection fetch; applying in memory! 

并且执行的SQL查询将缺少pagination子句:

 SELECT p.id AS id1_0_0_, c.id AS id1_1_1_, p.created_on AS created_2_0_0_, p.title AS title3_0_0_, c.created_on AS created_2_1_1_, c.post_id AS post_id4_1_1_, c.review AS review3_1_1_, c.post_id AS post_id4_1_0__, c.id AS id1_1_0__ FROM post p LEFT OUTER JOIN post_comment c ON p.id=c.post_id ORDER BY p.created_on 

这是因为Hibernate希望完全获取实体及其集合,如JOIN FETCH子句所示,而SQL级别的分页可能会截断ResultSet可能会在comments集合中留下具有较少元素的父Post实体。

HHH000104警告的问题在于Hibernate将获取PostPostComment实体的产品,并且由于结果集大小,查询响应时间将变得非常重要。

要解决此限制,您必须使用窗口函数查询:

 List posts = entityManager .createNativeQuery( "select * " + "from ( " + " select *, dense_rank() OVER (ORDER BY post_id) rank " + " from ( " + " select p.*, pc.* " + " from post p " + " left join post_comment pc on p.id = pc.post_id " + " order by p.created_on " + " ) p_pc " + ") p_pc_r " + "where p_pc_r.rank <= :rank", Post.class) .setParameter("rank", 10) .unwrap(NativeQuery.class) .addEntity("p", Post.class) .addEntity("pc", PostComment.class) .setResultTransformer(DistinctPostResultTransformer.INSTANCE) .getResultList(); 

有关使用窗口函数修复HHH000104问题以及DistinctPostResultTransformer的代码的更多详细信息,请查看本文 。