【问题标题】: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();
  • 没有。您不必使用本机查询。阅读链接的问答!!!

标签: java mysql jpa spring-data-jpa jpql


【解决方案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();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-11-13
              • 2018-12-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-03-08
              相关资源
              最近更新 更多