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将获取Post
和PostComment
实体的产品,并且由于结果集大小,查询响应时间将变得非常重要。
要解决此限制,您必须使用窗口函数查询:
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
的代码的更多详细信息,请查看本文 。
- 在Spring Framework 3.0中使用Hibernate和Jdbc
- java.math.BigInteger无法强制转换为java.lang.Long
- @OneToMany删除子项
- StAX – 从xml读取base64字符串到db
- 使用Tomcat和gradle进行Hibernate
- Hibernatevalidation注释 – validation至少一个字段不为空
- com.mchange.v2.resourcepool.CannotAcquireResourceException:ResourcePool无法从其主工厂或源获取资源
- Hibernate开启/关闭会话,DAO的正确方法
- Hibernate QueryTranslatorImpl HQL AST解析性能