你如何在HQL中进行限制查询?

ste*_*own 224 java hibernate hql hibernate3

在Hibernate 3中,有没有办法在HQL中执行以下MySQL限制?

select * from a_table order by a_table_column desc limit 0, 20;
Run Code Online (Sandbox Code Playgroud)

如果可能,我不想使用setMaxResults.这在旧版本的Hibernate/HQL中肯定是可能的,但似乎已经消失了.

ska*_*man 302

几年前,当被问及为什么这在Hibernate 2中工作但在Hibernate 3中不起作用时,这张贴在Hibernate论坛上:

在HQL中,限制从来都不是受支持的子句.您应该使用setMaxResults().

因此,如果它在Hibernate 2中有效,那似乎是巧合,而不是设计.我认为这是因为Hibernate 2 HQL解析器将替换它识别为HQL的查询位,并保留其余部分,因此您可以隐藏一些本机SQL.然而,Hibernate 3有一个合适的AST HQL Parser,并且它的宽容度要低得多.

我认为Query.setMaxResults()这是你唯一的选择.

  • 但是使用setMaxResults,运行第一个查询,然后在结果集上调用`setMaxResults`,它将从结果集中获取有限数量的结果行并将其显示给用户,在我的情况下,我有300万条记录被查询然后调用setMaxResults设置50条记录,但我不想这样做,而查询本身我想查询50条记录,有没有办法做到这一点? (48认同)
  • @Rachel使用`setMaxResults`,hibernate会将`limit`部分追加到查询中.它不会得到所有结果.您可以通过启用以下内容来检查它生成的查询:`<property name ="show_sql"> true </ property>` (17认同)
  • 我同意,但是当这些功能被丢弃时,它会使迁移成为王室的痛苦. (6认同)
  • 我认为Hibernate 3的方法更为正确.您对Hibernate的使用意味着与数据库无关,因此您必须以抽象的方式执行这些操作. (3认同)
  • 老帖子我知道.我完全同意雷切尔的观点.使用NHibernate(Hibernate的.Net端口),我最近从2升级到3同样的事情,顶部X现在抛出一个解析器错误.但是,当我在查询中添加setMaxResults时,它确实在生成的SQL中生成了一个TOP X(使用MsSql2008Dialect).这很好. (2认同)

Jes*_*ssu 139

 // SQL: SELECT * FROM table LIMIT start, maxRows;

Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);
Run Code Online (Sandbox Code Playgroud)

  • 我最喜欢这个,因为在这个答案中实际上提到了`setFirstResult`,而在这里和其他地方他们只是说`setMaxResults` this和`setMaxResults`,而没有提到如何设置偏移量. (6认同)

pjp*_*pjp 19

如果您不想setMaxResults()Query对象上使用,那么您可以始终恢复使用普通SQL.

  • 那并不是那么令人兴奋. (34认同)
  • 我也没有发现HQL令人兴奋.为什么不在数据库服务器上编写应用限制的视图,然后让HQL查看该视图:P (8认同)

tk_*_*tk_ 7

您可以轻松地使用分页来实现此目的。

    @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value = "true") })
    @Query("select * from a_table order by a_table_column desc")
    List<String> getStringValue(Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

您必须传递new PageRequest(0, 1)以获取记录并从列表中获取第一条记录。


Vla*_*cea 6

setFirstResultsetMaxResults Query方法

对于 JPA 和 Hibernate Query,该setFirstResult方法等效于OFFSET,该setMaxResults方法等效于 LIMIT:

List<Post> posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
Run Code Online (Sandbox Code Playgroud)

LimitHandler抽象

HibernateLimitHandler定义了特定于数据库的分页逻辑,如下图所示,Hibernate 支持许多特定于数据库的分页选项:

LimitHandler 实现

现在,根据您使用的底层关系数据库系统,上述 JPQL 查询将使用正确的分页语法。

MySQL

SELECT p.id AS id1_0_,
       p.created_on AS created_2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?, ?
Run Code Online (Sandbox Code Playgroud)

PostgreSQL

SELECT p.id AS id1_0_,
       p.created_on AS created_2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
Run Code Online (Sandbox Code Playgroud)

数据库服务器

SELECT p.id AS id1_0_,
       p.created_on AS created_on2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
OFFSET ? ROWS 
FETCH NEXT ? ROWS ONLY
Run Code Online (Sandbox Code Playgroud)

甲骨文

SELECT *
FROM (
    SELECT 
        row_.*, rownum rownum_
    FROM (
        SELECT 
            p.id AS id1_0_,
            p.created_on AS created_on2_0_,
            p.title AS title3_0_
        FROM post p
        ORDER BY p.created_on
    ) row_
    WHERE rownum <= ?
)
WHERE rownum_ > ?
Run Code Online (Sandbox Code Playgroud)

使用setFirstResult和的优点setMaxResults是 Hibernate 可以为任何受支持的关系数据库生成特定于数据库的分页语法。

而且,您不仅限于 JPQL 查询。您可以将setFirstResultsetMaxResults方法七用于本机 SQL 查询。

本机 SQL 查询

使用本机 SQL 查询时,您不必对特定于数据库的分页进行硬编码。Hibernate 可以将其添加到您的查询中。

因此,如果您在 PostgreSQL 上执行此 SQL 查询:

List<Tuple> 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();
Run Code Online (Sandbox Code Playgroud)

Hibernate 将其转换如下:

SELECT p.id AS id,
       p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
Run Code Online (Sandbox Code Playgroud)

酷,对吧?

超越基于 SQL 的分页

当您可以索引过滤和排序标准时,分页是很好的。如果您的分页要求意味着动态过滤,那么使用倒排索引解决方案(例如 ElasticSearch)是一种更好的方法。


Llu*_*nez 5

如果您不想使用setMaxResults,也可以使用Query.scroll而不是list,并获取所需的行.例如,用于分页.