Hibernate-HQL分页

Hibernate-HQL分页,hibernate,pagination,hql,Hibernate,Pagination,Hql,这是一个类似于以下问题的问题: 我正在尝试使用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.iden

这是一个类似于以下问题的问题:

我正在尝试使用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

绝对没有限制或偏移量

最可能的情况是,如果您使用HQL创建自己的查询,查询生成器方法无法解析自定义HQL查询并对其进行更改。因此,您应该在HQL查询的末尾添加
LIMIT?,?
语句,然后绑定偏移量参数。

根据第3.8.6节查询执行

应用setMaxResults的效果 或将FirstResult设置为包含 集合上的获取联接不可用 未定义

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


我通常使用一个单独的查询来获取所需对象的ID,并使用fetch连接将其传递到查询中

由于不过滤与命令实体的某些属性相关的结果集,因此还可以避免SQL连接,并为消息的命令配置延迟抓取。如果没有join,Hibernate将使用数据库分页功能

但是,您必须关心N+1 seletcs问题,即避免为每个延迟获取的commands属性选择一个选项。您可以通过在hibernate映射中设置批大小属性或在hibernate设置中全局设置hibernate.default\u batch\u fetch\u size属性来避免这种情况

例如:如果您在Hibernate会话中获取了100个消息对象,并将批处理大小设置为10,则当您首次调用消息对象的getCommands()时,Hibernate将获取10个不同消息对象的10个命令关联。查询的数量减少到10个,再加上获取一个原始消息的数量


看看这里:作者通过一个简单的例子比较了不同的获取策略

我们可以使用查询和条件界面来实现分页:

使用查询界面分页:

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 criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);            
List<Employee> list = criteria.list();
for(Employee emp: list) {            
    System.out.println(emp);
}
分页的查询接口有两种方法

1。查询setFirstResult(int起始位置): 此方法接受一个整数,该整数表示结果集中的第一行,从第0行开始

2。查询setMaxResult(int-maxResult): 此方法告诉Hibernate检索固定数量的对象。结合使用以上两种方法,我们可以在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 criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);            
List<Employee> list = criteria.list();
for(Employee emp: list) {            
    System.out.println(emp);
}
Query Query=session.createQuery(“来自员工”);
query.setFirstResult(5);
query.setMaxResults(10);
List=query.List();
对于(员工emp:列表){
系统输出打印项次(emp);
}
使用标准界面分页:

分页的条件接口有两种方法

1。标准setFirstResult(int firstResult):

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 criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);            
List<Employee> list = criteria.list();
for(Employee emp: list) {            
    System.out.println(emp);
}
设置要检索的第一个结果

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

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 criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);            
List<Employee> list = criteria.list();
for(Employee emp: list) {            
    System.out.println(emp);
}
设置要检索的对象数量的限制

示例:

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 criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);            
List<Employee> list = criteria.list();
for(Employee emp: list) {            
    System.out.println(emp);
}
Criteria=session.createCriteria(Employee.class);
标准:setFirstResult(5);
标准:setMaxResults(10);
List=criteria.List();
对于(员工emp:列表){
系统输出打印项次(emp);
}

我正在使用此解决方案:

/**
 * @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);
}
/**
*@param limitPerPage
*@param页
*@返回
*/
公共列表searchByPage(int-limitPerPage、int-page、字符串实体){
String sql=“从“+实体+”t”中选择t”;
Query Query=em.createQuery(sql)
.setFirstResult(计算偏移量(第页,限制每页))
.setMaxResults(limitPerPage);
返回query.getResultList();
}
/**
*@param页
*@返回
*/
专用整数计算偏移(整数页,整数限制){
返回((限制*页)-限制);
}

欢迎。

我认为您最初的例外是不正确的

发生的情况是Hibernate获取所有消息,并在加载完所有消息后>返回所需的消息


查询处理时发生的情况是,setFirstResult(calculateOffset(page,limitPerPage))被转换为偏移量,而setMaxResults(limitPerPage)被转换为限制量,这可能是一个错误。您能启用调试参数来显示SQL查询并查看实际执行的查询吗?SQL查询绝对没有限制或偏移SetFirstResult(elementsPerBlock*((第1页)+1))“-1+1”在这里似乎不正确:o)我理解您的意思有点困难。1) 如何在HQL查询的末尾追加SQL字符串?2) “绑定偏移参数”是什么意思?如何将分页与子选择一起使用?(我理解第二个想法,但我的交流可能变得非常健谈)编辑以删除对subselect的引用。如果使用subselect,它确实会破坏整个目的。虽然它会破坏目的,但我希望所有计算都在DB端完成,而不是在客户端完成。这就是为什么我相信如果一个子选择可以做分页,我会使用它。我不认为一个子选择可以做分页。当然,试试也无妨。你试过这个吗?Stevi Dete说这个词的效果还没有定义。你为什么不把它翻译成英语呢?我已经把这么多的英语代码翻译成葡萄牙语了,但我不知道这个词的意思。。。为什么你不能这样做