【问题标题】:Hibernate - HQL paginationHibernate - HQL 分页
【发布时间】:2011-09-14 22:38:57
【问题描述】:

这是一个类似的问题:HQL - row identifier for pagination

我正在尝试使用 HQL 实现分页。我有一个 PostgreSQL 数据库。

int elementsPerBlock = 10;
int page = 2; //offset = 2*10

String sqlQuery = "FROM Messages AS msg " +
                  " LEFT JOIN FETCH msg.commands AS cmd " +   
                  "ORDER BY msg.identifier ASC" ;

Query query = session.createQuery( sqlQuery )
                     .setFirstResult( elementsPerBlock * ( (page-1) +1 ) )
                     .setMaxResults( elementsPerBlock );

发生的情况是 Hibernate 获取所有消息,并在它们全部加载后返回所需的消息。

因此,Hibernate 获取 210000 个实体,而不是返回的 30 个(每个消息恰好有 2 个命令)。

有没有办法将开销减少 7000 倍?

编辑:我尝试添加 .setFetchSize( elementsPerBlock ) 。它没有帮助。

编辑2:生成的SQL查询是:

select ... 
from schemaName.messages messages0_ 
left outer join schemaName.send_commands commands1_ 
on messages0_.unique_key=commands1_.message_key 
order by messages0_.unique_identifier ASC

绝对没有限制或偏移

【问题讨论】:

  • 这可能是一个错误。能否启用调试参数以显示 SQL 查询并查看实际执行的查询?
  • SQL 查询绝对没有 LIMIT 或 OFFSET
  • setFirstResult( elementsPerBlock * ( (page-1) +1 ) ) 这里的“-1 +1”似乎不正确 :o)

标签: hibernate pagination hql


【解决方案1】:

根据JPA 2.0 specification,第 3.8.6 节查询执行,

应用 setMaxResults 的效果 或 setFirstResult 到涉及的查询 fetch joins 是 未定义。

它因数据库而异,根据我的经验,结果是 Hibernate 通常在内存中而不是在数据库查询级别进行分页。

我通常所做的是使用单独的查询来获取所需对象的 id,然后使用 fetch 连接将其传递到查询中。

【讨论】:

  • 如何将分页与子选择一起使用? (我理解第二个想法,但是我的交流会变得很健谈)
  • 已编辑以删除对子选择的引用。如果您使用子选择,它确实会破坏整个目的。
  • 虽然它会破坏目的,但我希望所有计算都在数据库端而不是客户端完成。这就是为什么我相信如果子选择可以进行分页,我会使用它。
  • 我不认为子选择可以进行分页。当然,尝试没有坏处。
【解决方案2】:

我正在使用这个解决方案:

/**
 * @param limitPerPage
 * @param page
 * @return
 */
public List<T> searchByPage(int limitPerPage, int page, String entity) {
    String sql = "SELECT t FROM " + entity + " t";
    Query query = em.createQuery(sql)
            .setFirstResult(calculateOffset(page, limitPerPage))
            .setMaxResults(limitPerPage);
    return query.getResultList();
}

/**
 * @param page
 * @return
 */
private int calculateOffset(int page, int limit) {
    return ((limit * page) - limit);
}

欢迎。

【讨论】:

  • 为什么不翻译成英文呢?
  • 当我不知道这个词是什么意思的时候,我已经将这么多英文代码翻译成葡萄牙语......为什么你不能这样做?
【解决方案3】:

我们可以通过Query and Criteria接口实现分页:

使用查询接口进行分页:

Query接口有两种分页方法。

1.查询 setFirstResult(int startPosition): 此方法采用一个整数,表示结果集中的第一行,从第 0 行开始。

2。查询 setMaxResults(int maxResult): 此方法告诉 Hibernate 检索固定数量的 maxResults 对象。结合使用以上两种方法,我们可以在我们的 Web 或 Swing 应用程序中构建一个分页组件。

示例:

Query query = session.createQuery("FROM Employee");
query.setFirstResult(5);
query.setMaxResults(10);
List<Employee> list = query.list();
for(Employee emp: list) {            
   System.out.println(emp);
}

使用标准接口进行分页:

Criteria 接口有两种分页方法。

1.条件 setFirstResult(int firstResult):

设置要检索的第一个结果。

2。列表项条件 setMaxResults(int maxResults):

对要检索的对象数量设置限制。

示例:

Criteria criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);            
List<Employee> list = criteria.list();
for(Employee emp: list) {            
    System.out.println(emp);
}

【讨论】:

  • 你试过了吗? Stevi Deter 说这种效果是不确定的。
【解决方案4】:

很可能,如果您使用 HQL 创建自己的查询,则查询构建器方法无法解析自定义 hql 查询并对其进行更改。因此,您应该将 LIMIT ?, ? 语句放在 HQL 查询的末尾,然后绑定偏移参数。

【讨论】:

  • 我无法理解您的意思。 1) 如何在 HQL 查询末尾附加 SQL 字符串? 2)“绑定偏移参数”是什么意思?
【解决方案5】:

由于您没有针对 command 实体的某些属性过滤结果集,因此您还可以避免 SQL 连接并为 message 的命令配置延迟获取.如果没有 join,Hibernate 将使用数据库分页功能。

但是,您必须关心 N+1 选择问题,即避免为每个延迟获取的 commands 属性进行一次选择。您可以通过在休眠映射中设置 batch-size 属性或在休眠设置中全局设置 hibernate.default_batch_fetch_size 属性来避免这种情况。

例如:如果您在 Hibernate 会话中获取了 100 个 message 对象并将 batch-size 设置为 10,那么 Hibernate 将获取 10 个 command当您第一次调用 message 对象的 getCommands() 时,10 个不同消息对象的 em> 关联。查询的数量减少到 10 加上原始的消息获取一个。

看这里:http://java.dzone.com/articles/hibernate-tuning-queries-using?page=0,1作者通过一个简单的例子对比了不同的抓取策略

【讨论】:

    【解决方案6】:

    我认为你原来的例外是不正确的。

    发生的情况是 Hibernate 获取所有消息,并 >在它们全部加载后返回所需的消息。

    查询处理时发生的情况是 setFirstResult(calculateOffset(page, limitPerPage)) 被转换为 OFFSET 而 setMaxResults(limitPerPage) 被转换为 LIMIT

    【讨论】:

      猜你喜欢
      • 2011-02-08
      • 1970-01-01
      • 2012-08-17
      • 2012-04-22
      • 2013-08-25
      • 2016-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多