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

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

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

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

366754 次浏览

如果你不想在Query对象上使用setMaxResults(),那么你总是可以恢复到使用普通SQL。

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

Limit是从来没有一个支持的子句 在HQL。你是用来使用的 setMaxResults () . < / p >

因此,如果它能在Hibernate 2中工作,那似乎是巧合,而不是设计。我认为,这是因为Hibernate 2 HQL解析器将替换它识别为HQL的查询,并保留其余部分,所以你可以潜入一些本地SQL。然而,Hibernate 3有一个合适的AST HQL解析器,它不那么宽容。

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

如果不想使用setMaxResults,也可以使用Query。滚动而不是列表,并获取您想要的行。例如,对于分页很有用。

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

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

这适用于我没有使用setmaxResults();

只在最后一个(在本例中是5)中提供最大值,而不使用关键字limit。 : P < / P >
 // SQL: SELECT * FROM table LIMIT start, maxRows;


Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);

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

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

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

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

你需要编写一个本机查询,参考

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

您可以很容易地为此使用分页。

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

你必须传递__abc0来获取记录和从列表中获取第一条记录。

setFirstResultsetMaxResults Query方法

对于JPA和Hibernate QuerysetFirstResult方法相当于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支持许多特定于数据库的分页选项:

LimitHandler implementations

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

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

而且,您不仅限于JPQL查询。你可以在本地SQL查询中使用setFirstResultsetMaxResults方法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)是更好的方法。

你可以使用下面的查询

NativeQuery<Object[]> query = session.createNativeQuery("select * from employee limit ?");
query.setparameter(1,1);

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

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

你可以在这个链接获得演示应用程序。

你可以使用下面的查询

NativeQuery<Object[]> query = session.createNativeQuery("select * from employee limit ?1")
query.setparameter(1,1);