【问题标题】:Is there are way to scroll results with JPA/hibernate?有没有办法用 JPA/hibernate 滚动结果?
【发布时间】:2010-11-12 22:31:50
【问题描述】:

我在Toplink找到了一些提示

Query query = em.createQuery("SELECT e FROM Employee e ORDER BY e.lastName ASC, e.firstName ASC");
query.setHint("eclipselink.cursor.scrollable", true);
ScrollableCursor scrollableCursor = (ScrollableCursor)query.getSingleResult();
List<Employee> emps = scrollableCursor.next(10);

是否有 jpa/hibernate 替代方案?

【问题讨论】:

    标签: java hibernate orm jpa toplink


    【解决方案1】:

    据我所知,JPA 对此没有任何标准。

    对于 Hibernate,我所知道的最接近的替代方案是 Query / ScrollableResults API。来自文档:

    10.4.1.6. Scrollable iteration

    如果您的 JDBC 驱动程序支持 可滚动的结果集,查询 接口可用于获取 允许的 ScrollableResults 对象 查询的灵活导航 结果。

    Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
                                "order by cat.name");
    ScrollableResults cats = q.scroll();
    if ( cats.first() ) {
    
        // find the first name on each page of an alphabetical list of cats by name
        firstNamesOfPages = new ArrayList();
        do {
            String name = cats.getString(0);
            firstNamesOfPages.add(name);
        }
        while ( cats.scroll(PAGE_SIZE) );
    
        // Now get the first page of cats
        pageOfCats = new ArrayList();    
        cats.beforeFirst();    
        int i=0;    
        while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
    
    }
    
    cats.close()
    

    注意一个打开的数据库连接 为此需要光标 功能。采用 setMaxResult()/setFirstResult()如果你 需要离线分页功能。

    【讨论】:

    • 别忘了把 close() 放到 try ... finally.
    【解决方案2】:

    从其他答案来看,JPA 不支持直接滚动,但是如果你使用 Hibernate 作为 JPA 实现,你可以这样做

    javax.persistence.Query query = entityManager.createQuery("select foo from bar");
    org.hibernate.Query hquery = query.unwrap(org.hibernate.Query);
    ScrollableResults results = hquery.scroll(ScrollMode.FORWARD_ONLY);
    

    访问底层 Hibernate api 进行滚动,但您可以使用 JPA 查询的所有功能。 (至少对于条件查询,JPA api 有一些旧 Hibernate api 中没有的特性。)

    【讨论】:

      【解决方案3】:

      在基于List&lt;E&gt;实例的大型项目代码中处理大量实体时, 我必须编写一个非常有限的 List 实现,仅支持 Iterator 来浏览 ScrollableResults,而无需使用 List&lt;E&gt; 重构所有服务实现和方法原型。

      此实现在我的IterableListScrollableResults.java Gist 中可用

      它还会定期从会话中刷新 Hibernate 实体。这是一种使用它的方法,例如,当将所有未归档的实体从 DB 导出为带有 for 循环的文本文件时:

      Criteria criteria = getCurrentSession().createCriteria(LargeVolumeEntity.class);
      criteria.add(Restrictions.eq("archived", Boolean.FALSE));
      criteria.setReadOnly(true);
      criteria.setCacheable(false);
      List<E> result = new IterableListScrollableResults<E>(getCurrentSession(),
              criteria.scroll(ScrollMode.FORWARD_ONLY));
      for(E entity : result) {
          dumpEntity(file, entity);
      }
      

      希望对你有所帮助

      【讨论】:

        【解决方案4】:

        在 JPA 中,您可以使用 query.setFirstResult 和 query.setMaxResults

        【讨论】:

        • 那不是滚动的。您每次都触发一个新查询,并且开销确实增加了。此外,您需要对某些内容进行排序以获得可靠的分页,这也会增加查询时间。不幸的是,它似乎是获得类似滚动的唯一方法(如果不是性能,在功能上)。
        • 您还可以跳过或复制一些记录,以防您要“滚动”实时数据库,在线添加/删除数据,以及在页面边界附近发生添加/删除...
        【解决方案5】:

        也可以选择使用 Spring Data。在那里,您可以指定查询并将“PageRequest”作为参数传递,您可以在其中指明页面大小和页码:

        Page<User> users = repository.findAll(new PageRequest(1, 20));
        

        为此,您需要扩展 PagingAndSortingRepository。

        作为对结果进行分页的另一种选择。

        当然,在下面,它使用 Hibernate、Toplink 或您配置的任何 JPA 实现。

        【讨论】:

          猜你喜欢
          • 2014-07-26
          • 2021-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-16
          • 2021-01-02
          • 1970-01-01
          • 2020-09-30
          相关资源
          最近更新 更多