JPQL 中的 LIMIT 子句替代方案是啥?
Posted
技术标签:
【中文标题】JPQL 中的 LIMIT 子句替代方案是啥?【英文标题】:What is the LIMIT clause alternative in JPQL?JPQL 中的 LIMIT 子句替代方案是什么? 【发布时间】:2017-11-17 20:21:30 【问题描述】:我正在使用在 JPQL 中实现的 PostgreSQL 查询。
这是一个运行良好的示例原生 psql 查询,
SELECT * FROM students ORDER BY id DESC LIMIT 1;
JPQL 中的相同查询不起作用,
@Query("SELECT s FROM Students s ORDER BY s.id DESC LIMIT 1")
Students getLastStudentDetails();
好像 LIMIT 子句在 JPQL 中不起作用。
根据 JPA 文档,我们可以使用 setMaxResults/setFirstResult
,谁能告诉我如何在上面的查询中使用它?
【问题讨论】:
@NeilStockton 好吧,我有点困惑,现在如何在上面的 jpql 查询中使用 setMaxResults/setFirstResult? 我用过这个也对我有用@Query(value = "SELECT * FROM students ORDER BY id DESC LIMIT 1", nativeQuery = true) Object getLastStudentDetails();
没有。您不必使用本机查询。阅读链接的问答!!!
***.com/questions/34640488/… 的重复,并检查reference guide 或如何编写query methods。
【参考方案1】:
您使用的 JPQL 不支持这样的限制结果。使用原生 JPQL 时,您应该使用 setMaxResults
来限制结果。
但是,您使用的是 Spring Data JPA,这基本上使它很容易做到。请参阅参考指南中的here,了解如何根据查询限制结果。在您的情况下,find 方法将完全满足您的要求。
findFirstByOrderById();
您还可以在查询中使用Pageable
参数,而不是LIMIT
子句。
@Query("SELECT s FROM Students s ORDER BY s.id DESC")
List<Students> getLastStudentDetails(Pageable pageable);
然后在您的调用代码中执行类似的操作(如参考指南中的here 所述)。
getLastStudentDetails(PageRequest.of(0,1));
两者都应该产生相同的结果,而无需求助于普通 SQL。
【讨论】:
new PageRequest(0,1) 对我有用,而不是 new PageableRequest。我正在使用 Spring 1.5.6。 JPA 2.1 有什么变化吗? 您的代码不起作用,因为 1)LIMIT 1
in @Query
和 2) getLastStudentDetails
具有 Pageable
类型的参数但返回单个对象。这将在应用启动时失败 (IllegalStateException: Method has to have one of the following return types! [interface org.springframework.data.domain.Slice, interface java.util.List, interface org.springframework.data.domain.Page]
)
new PageRequest
已被弃用。现在使用PageRequest.of(page, size)
使用 Pageable 而不是 LIMIT 子句的问题是 Pageable 会导致查询的第二个 count(..) 版本也被执行,如果查询很昂贵,这会导致它需要两次时间,
计数不应该花费太长时间,如果它确实检查了您的查询和索引。【参考方案2】:
如 cmets 中所述,JPQL 不支持 LIMIT
关键字。
您可以使用 setMaxResults
来实现这一点,但如果您想要的只是一个项目,那么请使用 getSingleResult
- 如果没有找到项目,它将引发异常。
因此,您的查询将类似于:
TypedQuery<Student> query = entityManager.createQuery("SELECT s FROM Students s ORDER BY s.id DESC", Student.class);
query.setMaxResults(1);
如果要设置特定的起始偏移量,请使用query.setFirstResult(initPosition)
;太
【讨论】:
嗨,我用过这个也对我有用@Query(value = "SELECT * FROM students ORDER BY id DESC LIMIT 1", nativeQuery = true) Object getLastStudentDetails();
^^ 如果要使用原生查询,那么使用 Hibernate 毫无意义。
@SiddharthSachdeva 是的,是的。
不正确。如果您的应用程序有数十个实体和数十个使用 Hibernate 或 JPA 完成的查询,并且在维护期间您发现需要转义一次到本机 SQL,您为什么不这样做?
@SiddharthSachdeva 您应该始终选择最适合您需求的技术或方法 - 如果“休眠方式”在特定情况下不是最佳选择,我们不应该仅仅因为它是很酷。【参考方案3】:
您好,获取单行并在 jpql 中使用 LIMIT,我们可以告诉 jpql 是否是本机查询。
(使用 -nativeQuery=true)
下面是用法
@Query("SELECT s FROM Students s ORDER BY s.id DESC LIMIT 1", nativeQuery=true)
Students getLastStudentDetails();
【讨论】:
现在是原生 SQL 语句,不是 JPQL。【参考方案4】:您不能在HQL
中使用Limit
,因为Limit
依赖于数据库供应商,因此Hibernate
不允许通过HQL
查询。
您可以实现的一种方法是使用子查询:
@Query("FROM Students st WHERE st.id = (SELECT max(s.id) FROM Students s)")
Students getLastStudentDetails();
【讨论】:
【参考方案5】:JPQL 不允许在 HQL 生成的查询中添加 limit 关键字。你会得到以下异常。
org.hibernate.hql.internal.ast.QuerySyntaxException:意外令牌: 1号线附近的LIMIT
不过不用担心,在 HQL 生成的查询中可以通过以下步骤使用 limit 关键字。
Sort.by(sortBy).descending() // 按降序获取记录
pageSize = 1 // 从降序结果集中取出第一条记录。
参考以下服务类
服务:
@Autowired
StudentRepository repository;
public List<Student> getLastStudentDetails(Integer pageNo, Integer pageSize, String sortBy)
Integer pageNo = 0;
Integer pageSize = 1;
String sortBy = "id";
Pageable paging = PageRequest.of(pageNo, pageSize, Sort.by(sortBy).descending());
Slice<Student> pagedResult = repository.findLastStudent(paging);
return pagedResult.getContent();
您的存储库接口应该实现 PagingAndSortingRepository
存储库:
public interface StudentRepository extends JpaRepository<Student,Long>, PagingAndSortingRepository<Student,Long>
@Query("select student from Student student")
Slice<Student> findLastStudent(Pageable paging);
这会将限制关键字添加到您可以在控制台中看到的查询中。希望这会有所帮助。
【讨论】:
【参考方案6】:硬编码分页(new PageRequest(0, 1)
)以实现只获取一条记录。
@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)
来获取记录并从列表中获取第一条记录。
【讨论】:
【参考方案7】:你可以这样使用:
@Repository
public interface ICustomerMasterRepository extends CrudRepository<CustomerMaster, String>
@Query(value = "SELECT max(c.customer_id) FROM CustomerMaster c ")
public String getMaxId();
【讨论】:
【参考方案8】:这是十大服务(这是一个有用的例子)
存储库 (在Query中,我通过构造函数将分数实体解析为ScoreTo(DTO类))
@Repository
public interface ScoreRepository extends JpaRepository<Scores, UUID>
@Query("SELECT new com.example.parameters.model.to.ScoreTo(u.scoreId , u.level, u.userEmail, u.scoreLearningPoints, u.scoreExperiencePoints, u.scoreCommunityPoints, u.scoreTeamworkPoints, u.scoreCommunicationPoints, u.scoreTotalPoints) FROM Scores u "+
"order by u.scoreTotalPoints desc")
List<ScoreTo> findTopScore(Pageable pageable);
服务
@Service
public class ScoreService
@Autowired
private ScoreRepository scoreRepository;
public List<ScoreTo> getTopScores()
return scoreRepository.findTopScore(PageRequest.of(0,10));
【讨论】:
【参考方案9】:正确的方法是这样写你的JPA接口方法
public interface MyRepository extends PagingAndSortingRepository<EntityClass, KeyClass>
List<EntityClass> findTop100ByOrderByLastModifiedDesc();
在方法名称中,“100”表示您需要多少行,否则您将在限制子句中放入。 “LastModified”也是您要排序的列。
PagingAndSortingRepository 或 CrudRepository,两者都适用。
为了完整起见,OP的接口方法是
List<Students> findTop1ByIdDesc();
【讨论】:
以上是关于JPQL 中的 LIMIT 子句替代方案是啥?的主要内容,如果未能解决你的问题,请参考以下文章
等效于 SQL SERVER 的 MySQL LIMIT 子句
Stargate REST API 是不是支持 LIMIT 子句?