在Hibernate 3中,是否有一种方法可以在HQL中实现与以下MySQL限制相同的功能?

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

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


当前回答

你需要写一个本地查询,参考这个。

@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);

其他回答

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

这为我工作,没有使用setmaxResults();

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

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

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

setFirstResult和setMaxResults查询方法

对于JPA和Hibernate查询,setFirstResult方法相当于OFFSET, setMaxResults方法相当于LIMIT:

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

LimitHandler抽象

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

现在,根据所使用的底层关系数据库系统,上面的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 Server

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

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

而且,您不仅限于JPQL查询。对于本地SQL查询,可以使用setFirstResult和setMaxResults方法7。

本地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)是更好的方法。

你需要写一个本地查询,参考这个。

@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);