Hibernate-HQL分页

x6h2sr28  于 2022-11-14  发布在  其他
关注(0)|答案(6)|浏览(188)

这是一个类似于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

绝对没有限制或偏移量

egmofgnx

egmofgnx1#

根据JPA 2.0 specification,第3.8.6节查询执行,
将setMaxResults或setFirstResult应用于涉及集合上的FETCH联接的查询的效果未定义。
它因数据库而异,根据我的经验,结果是Hibernate通常在内存中执行分页,而不是在数据库查询级别。
我通常使用一个单独的查询来获取所需对象的ID,并通过FETCH连接将其传递到查询中。

o3imoua4

o3imoua42#

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

/**
 * @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);
}

欢迎。

2q5ifsrm

2q5ifsrm3#

我们可以通过查询和条件接口来实现分页:

使用查询接口进行分页:

用于分页的查询接口有两种方法。

**1.Query 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 First StResult):

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

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);
}
bqf10yzr

bqf10yzr4#

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

jmp7cifd

jmp7cifd5#

由于您没有针对COMMAND实体的某些属性对结果集进行过滤,因此也可以避免SQL JOIN,并为MESSAGE的命令配置延迟抓取。如果没有JOIN,Hibernate将使用数据库的分页能力。
然而,您必须关心N+1个seletcs问题,即避免为每个延迟获取的命令属性执行一次SELECT操作。您可以通过在HibernateMap中设置Batch-Size属性或在Hibernate设置中全局设置Hibernate.Default_Batch_Fetch_Size来避免此问题。
例如:如果您在Hibernate会话中获取了100个Message对象,并将Batch-Size设置为10,则当您第一次调用Message对象的getCommands()时,Hibernate将获取10个不同消息对象的10个命令关联。查询的数量减少到10个加上原始的获取消息的查询。
看看这里:http://java.dzone.com/articles/hibernate-tuning-queries-using?page=0,1作者通过一个简单的例子比较了不同的获取策略

zpjtge22

zpjtge226#

我认为你原来的例外是不正确的。
发生的情况是,Hibernate获取所有消息,并在所有消息加载后返回所需的消息。
查询处理过程中发生的情况是,setFirstResult(culateOffset(page,limitPerPage))被转换为偏移量,而setMaxResults(LimitPerPage)被转换为Limit

相关问题