261

在 Hibernate 3 中,有没有办法在 HQL 中执行相当于以下 MySQL 限制的方法?

select * from a_table order by a_table_column desc limit 0, 20;

如果可能的话,我不想使用 setMaxResults 。这在旧版本的 Hibernate/HQL 中绝对是可能的,但它似乎已经消失了。

4

14 回答 14

331

这是几年前在 Hibernate 论坛上发布的,当时被问及为什么这在 H​​ibernate 2 中有效但在 Hibernate 3 中无效:

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

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

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

于 2009-08-06T15:37:53.363 回答
153
 // SQL: SELECT * FROM table LIMIT start, maxRows;

Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);
于 2011-02-14T09:28:44.673 回答
21

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

于 2009-08-06T15:36:54.597 回答
6

setFirstResultsetMaxResults Query方法_

对于 JPA 和 Hibernate QuerysetFirstResult方法等价于OFFSETsetMaxResults方法等价于 LIMIT:

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

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 ?, ?

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 ?

SQL 服务器

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

甲骨文

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_ > ?

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

而且,您不仅限于 JPQL 查询。您可以将setFirstResultandsetMaxResults方法七用于本机 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();

Hibernate 会将其转换如下:

SELECT p.id AS id,
       p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?

很酷,对吧?

超越基于 SQL 的分页

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

于 2020-02-25T07:35:54.747 回答
5

如果您不想使用 setMaxResults,您也可以使用 Query.scroll 代替 list,并获取您想要的行。例如对分页很有用。

于 2009-12-08T18:10:18.713 回答
5

您可以轻松地为此使用分页。

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

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

于 2019-07-03T10:39:59.840 回答
2

您需要编写本机查询,请参阅

@Query(value =
    "SELECT * FROM user_metric UM WHERE UM.user_id = :userId AND UM.metric_id = :metricId LIMIT :limit", nativeQuery = true)
List<UserMetricValue> findTopNByUserIdAndMetricId(
    @Param("userId") String userId, @Param("metricId") Long metricId,
    @Param("limit") int limit);
于 2018-04-27T05:57:12.053 回答
1

String hql = "select userName from AccountInfo order by points desc 5";

这对我有用,但不使用setmaxResults();

只需在最后一个(在本例中为 5)中提供最大值,而不使用关键字limit。:P

于 2011-01-12T06:46:30.443 回答
0

我的观察是,即使您在 HQL(hibernate 3.x)中有限制,它也会导致解析错误或被忽略。(如果在limit前有order by + desc/asc会被忽略,如果在limit前没有desc/asc会导致解析错误)

于 2010-07-27T06:11:34.747 回答
0

如果可以在此模式下管理限制

public List<ExampleModel> listExampleModel() {
    return listExampleModel(null, null);
}

public List<ExampleModel> listExampleModel(Integer first, Integer count) {
    Query tmp = getSession().createQuery("from ExampleModel");

    if (first != null)
        tmp.setFirstResult(first);
    if (count != null)
        tmp.setMaxResults(count);

    return (List<ExampleModel>)tmp.list();
}

这是处理限制或列表的非常简单的代码。

于 2011-10-28T07:01:00.360 回答
0
Criteria criteria=curdSession.createCriteria(DTOCLASS.class).addOrder(Order.desc("feild_name"));
                criteria.setMaxResults(3);
                List<DTOCLASS> users = (List<DTOCLASS>) criteria.list();
for (DTOCLASS user : users) {
                System.out.println(user.getStart());
            }
于 2016-07-16T10:36:21.327 回答
0

您可以使用以下查询

NativeQuery<Object[]> query = session.createNativeQuery(select * from employee limit ?)
query.setparameter(1,1);
于 2020-02-28T09:54:06.387 回答
0

下面的代码片段用于使用 HQL 执行限制查询。

Query query = session.createQuery("....");
query.setFirstResult(startPosition);
query.setMaxResults(maxRows);

您可以在此链接获得演示应用程序。

于 2020-03-17T08:47:01.357 回答
-2
@Query(nativeQuery = true,
       value = "select from otp u where u.email =:email order by u.dateTime desc limit 1")
public List<otp> findOtp(@Param("email") String email);
于 2019-03-15T07:10:48.683 回答