在 Hibernate 3 中,有没有办法在 HQL 中执行相当于以下 MySQL 限制的方法?
select * from a_table order by a_table_column desc limit 0, 20;
如果可能的话,我不想使用 setMaxResults 。这在旧版本的 Hibernate/HQL 中绝对是可能的,但它似乎已经消失了。
Hibernate-5.0.12
。这仍然不可用吗?正如@Rachel 在@skaffman 的回答中所注意到的那样,获得一百万条左右的记录然后对其应用过滤器- setMaxResults
将非常繁重。
This was posted 在几年前的 Hibernate 论坛上,当被问及为什么这在 Hibernate 2 中有效但在 Hibernate 3 中无效时:
在 HQL 中,限制从来都不是受支持的子句。您应该使用 setMaxResults()。
因此,如果它在 Hibernate 2 中起作用,那似乎是巧合,而不是设计使然。我认为这是因为 Hibernate 2 HQL 解析器将替换它识别为 HQL 的查询位,并保持其余部分不变,因此您可以潜入一些本机 SQL。然而,Hibernate 3 有一个适当的 AST HQL 解析器,而且它的宽容度要低得多。
我认为 Query.setMaxResults()
确实是您唯一的选择。
// SQL: SELECT * FROM table LIMIT start, maxRows;
Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);
setFirstResult
,而在这里和其他地方他们只是说 setMaxResults
这个和 setMaxResults
that 而没有提到如何设置偏移量。
如果您不想在 Query
对象上使用 setMaxResults()
,那么您可以随时恢复使用普通 SQL。
setFirstResult 和 setMaxResults 查询方法
对于 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();
LimitHandler 抽象
Hibernate LimitHandler
定义了特定于数据库的分页逻辑,如下图所示,Hibernate 支持许多特定于数据库的分页选项:
https://i.stack.imgur.com/IGtD2.png
现在,根据您使用的底层关系数据库系统,上述 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_ > ?
使用 setFirstResult
和 setMaxResults
的优点是 Hibernate 可以为任何受支持的关系数据库生成特定于数据库的分页语法。
而且,您不仅限于 JPQL 查询。您可以将 setFirstResult
和 setMaxResults
方法七用于本机 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)是一种更好的方法。
如果您不想使用 setMaxResults,您也可以使用 Query.scroll 代替 list,并获取您想要的行。例如对分页很有用。
setMaxResults()
首先加载内存中的每条记录,然后创建一个子列表,当有数十万或更多记录时,服务器会因为内存不足而崩溃。但是,我可以通过 QueryImpl hibernateQuery = query.unwrap(QueryImpl.class)
从 JPA 类型查询转到 Hibernate 查询,然后我可以按照您的建议使用 scroll()
方法。
您可以轻松地为此使用分页。
@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)
来获取记录并从列表中获取第一条记录。
Pageable
作为方法中的参数并调用它发送“new PageRequest(0, 20)
”我得到前 20 条记录.谢谢。
您需要编写原生查询,请参阅 this。
@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
我的观察是,即使您在 HQL(hibernate 3.x)中有限制,它也会导致解析错误或被忽略。 (如果在limit前有order by + desc/asc会被忽略,如果在limit前没有desc/asc会导致解析错误)
如果可以在此模式下管理限制
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());
}
您可以使用以下查询
NativeQuery<Object[]> query = session.createNativeQuery(select * from employee limit ?)
query.setparameter(1,1);
下面的代码片段用于使用 HQL 执行限制查询。
Query query = session.createQuery("....");
query.setFirstResult(startPosition);
query.setMaxResults(maxRows);
您可以在此 link 获得演示应用程序。
@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);
setMaxResults
,这将从结果集中获取有限数量的结果行并将其显示给用户,在我的情况下,我有 300 万条记录被查询然后正在调用setMaxResults 设置 50 条记录,但我不想这样做,而查询本身我想查询 50 条记录,有没有办法做到这一点?setMaxResults
hibernate 会将limit
部分附加到查询中。它不会得到所有的结果。您可以通过启用来检查它产生的查询:<property name="show_sql">true</property>