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 子句

类似子句 JPQL 中的参数

Stargate REST API 是不是支持 LIMIT 子句?

JPA JPQL IN 子句:如何在 JPA 中使用 IN 子句?

JPA JPQL IN子句:如何在JPA中使用IN子句?

解决方案 兼容 Oracle 和 MySQL for LIMIT 子句