【问题标题】:setMaxResults for Spring-Data-JPA annotation?用于 Spring-Data-JPA 注释的 setMaxResults?
【发布时间】:2012-03-08 00:23:26
【问题描述】:

我正在尝试将 Spring-Data-JPA 合并到我的项目中。 让我困惑的一件事是如何通过注释实现 setMaxResults(n) ?

例如,我的代码:

public interface UserRepository extends CrudRepository<User , Long>
{
  @Query(value="From User u where u.otherObj = ?1 ")
  public User findByOtherObj(OtherObj otherObj);
}

我只需要从 otherObj 返回one (and only one) User,但我找不到注释 maxResults 的方法。有人可以给我一个提示吗?

(mysql抱怨:

com.mysql.jdbc.JDBC4PreparedStatement@5add5415: select user0_.id as id100_, user0_.created as created100_ from User user0_ where user0_.id=2 limit ** NOT SPECIFIED **
WARN  util.JDBCExceptionReporter - SQL Error: 0, SQLState: 07001
ERROR util.JDBCExceptionReporter - No value specified for parameter 2

)

我找到了一个链接:https://jira.springsource.org/browse/DATAJPA-147, 我试过但失败了。现在好像不行了? 为什么 Spring-Data 没有内置这么重要的功能?

如果我手动实现此功能:

public class UserRepositoryImpl implements UserRepository

我必须在CrudRepository 中实现大量预定义的方法,这太糟糕了。

环境:spring-3.1、spring-data-jpa-1.0.3.RELEASE.jar、spring-data-commons-core-1.1.0.RELEASE.jar

【问题讨论】:

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


    【解决方案1】:

    从 Spring Data JPA 1.7.0(Evans 发布系列)开始。

    您可以使用新引入的TopFirst 关键字来定义这样的查询方法:

    findTop10ByLastnameOrderByFirstnameAsc(String lastname);
    

    Spring Data 会自动将结果限制为您定义的数字(如果省略,则默认为 1)。请注意,结果的顺序在这里变得相关(通过示例中看到的OrderBy 子句或通过将Sort 参数传递给方法)。在涵盖new features of the Spring Data Evans release traindocumentation 的博客文章中阅读更多信息。

    对于以前的版本

    为了只检索数据片段,Spring Data 使用了分页抽象,它在请求端带有一个Pageable 接口,在结果端也有一个Page 抽象。所以你可以从

    public interface UserRepository extends Repository<User, Long> {
    
      List<User> findByUsername(String username, Pageable pageable);
    }
    

    并像这样使用它:

    Pageable topTen = new PageRequest(0, 10);
    List<User> result = repository.findByUsername("Matthews", topTen);
    

    如果您需要知道结果的上下文(实际上是哪个页面?是第一个页面吗?总共有多少个?),请使用Page 作为返回类型:

    public interface UserRepository extends Repository<User, Long> {
    
      Page<User> findByUsername(String username, Pageable pageable);
    }
    

    然后客户端代码可以执行以下操作:

    Pageable topTen = new PageRequest(0, 10);
    Page<User> result = repository.findByUsername("Matthews", topTen);
    Assert.assertThat(result.isFirstPage(), is(true));
    

    如果您使用Page 作为返回类型,我们不会触发要执行的实际查询的计数投影,因为我们需要找出总共有多少元素来计算元数据。除此之外,请确保您确实为PageRequest 配备了排序信息以获得稳定的结果。否则你可能会触发两次查询并得到不同的结果,即使下面的数据没有改变。

    【讨论】:

    • 谢谢,但我仍然希望有一个“基于注释”的解决方案。因为在这种情况下,“Page / Pageable”太过分了。并且客户端必须创建一个 Pageable/Page 来检索“唯一一个”结果......使用起来非常不友好。看来你是负责 Spring-Data 的,希望你能进一步研究这个问题:stackoverflow.com/questions/9276461/…。你能确认是不是 Spring-Data 的 bug 吗?
    • + 这行得通,谢谢,但基于注释的解决方案在新版本中会更好
    • 这里触发了一个计数查询,如果我们想要一个有限的查询,这是完全没有必要的。
    • 如果你使用List作为方法的返回类型,则不会。
    • 我认为TopFirst关键字不适用于使用@Query注解的方法?只有那些使用基于方法名的查询生成?
    【解决方案2】:

    如果您使用的是 Java 8 和 Spring Data 1.7.0,如果您想将 @Query 注释与设置最大结果相结合,则可以使用默认方法:

    public interface UserRepository extends PagingAndSortingRepository<User,Long> {
      @Query("from User u where ...")
      List<User> findAllUsersWhereFoo(@Param("foo") Foo foo, Pageable pageable);
    
      default List<User> findTop10UsersWhereFoo(Foo foo) {
        return findAllUsersWhereFoo(foo, new PageRequest(0,10));
      }
    
    }
    

    【讨论】:

    • 可能对单个结果有用Stream&lt;User&gt; ... {...} default Optional&lt;User&gt; ... { ...findAny() }
    【解决方案3】:

    有一种方法可以提供相当于“a setMaxResults(n) by annotation”的方法,如下所示:

    public interface ISomething extends JpaRepository<XYZ, Long>
    {
        @Query("FROM XYZ a WHERE a.eventDateTime < :before ORDER BY a.eventDateTime DESC")
        List<XYZ> findXYZRecords(@Param("before") Date before, Pageable pageable);
    }
    

    当一个可分页作为参数发送时,这应该可以解决问题。 例如,要获取前 10 条记录,您需要将 pageable 设置为此值:

    new PageRequest(0, 10)
    

    【讨论】:

    • 如果你使用的是 Pagable 那么它的返回 Page 而不是 List
    • @Arundev 错误 - List 完美运行(并避免a previous comment 中已经提到的不必要的count 查询)
    【解决方案4】:

    Use Spring Data Evans (1.7.0 RELEASE)

    Spring Data JPA 的新版本与另一个模块列表一起称为Evans 具有使用关键字Top20First 来限制查询结果的功能,

    所以你现在可以写

    List<User> findTop20ByLastname(String lastname, Sort sort);
    

    List<User> findTop20ByLastnameOrderByIdDesc(String lastname);
    

    或单个结果

    List<User> findFirstByLastnameOrderByIdDesc(String lastname);
    

    【讨论】:

    • 可选 findFirstByLastnameOrderByIdDesc(String lastname);
    • 获得top20结果后,使用分页方式进入网站下一页时,如何获得接下来的20个结果?
    • @kittu,这当然是另一个问题,但您需要传递一个 Pageable 对象。查看春季文档
    • 为什么他们让该方法返回一个该死的列表,如果它被指定为 FIRST ??
    • 最好将最后一个方法 (findFirstByLastnameOrderByIdDesc) 的返回类型写为 Optional&lt;User&gt; 甚至只是 User
    【解决方案5】:

    对我来说最好的选择是原生查询:

    @Query(value="SELECT * FROM users WHERE other_obj = ?1 LIMIT 1", nativeQuery = true)
    User findByOhterObj(OtherObj otherObj);
    

    【讨论】:

    • 不确定 Hibernate 是否支持限制:forum.hibernate.org/viewtopic.php?f=9&t=939314
    • 打破了整个概念!最好改用 EntityManager!
    • @Code.IT 我传播 KISS 概念。除了添加的 JPA nativeQuery 注释参数之外,不要忽略。
    • @GKislin 比你必须重命名你的方法,比如 findLimitOneByOtherObj。此外,如果 other_obj 不是唯一的,您也忘记添加会导致错误结果的 OrderBy。否则,在唯一列上的 where 语句应该足够了,没有限制
    • LIMIT 关键字不是 hibernate 而是 postgres/mysql
    【解决方案6】:

    new PageRequest(0,10) 在较新的 Spring 版本中不起作用(我使用的是 2.2.1.RELEASE)。基本上,构造函数有一个附加参数Sort 类型。此外,构造函数是protected,因此您必须使用其子类之一或调用其of 静态方法:

    PageRequest.of(0, 10, Sort.sort(User.class).by(User::getFirstName).ascending()))
    

    也可以省略Sort参数的使用,隐式使用默认排序(按pk排序等):

    PageRequest.of(0, 10)
    

    你的函数声明应该是这样的:

    List<User> findByUsername(String username, Pageable pageable)
    

    函数将是:

    userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
    

    【讨论】:

      【解决方案7】:

      也可以使用@QueryHints。下面的示例使用 org.eclipse.persistence.config.QueryHints#JDBC_MAX_ROWS

      @Query("SELECT u FROM User u WHERE .....")
      @QueryHints(@QueryHint(name = JDBC_MAX_ROWS, value = "1"))
      Voter findUser();
      

      【讨论】:

      • 我已经测试了这段代码,但它不起作用。也不例外,但没有适当的结果。此外,关于 QueryHints 的文档也很薄。见下文。 docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/…
      • IIRC,没有保证会遵循查询提示。这只是将“友好建议”传递给实施的一种方式。
      • 我在 Hibernate 中使用@QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")}) 尝试它,但别名:( 不起作用
      • org.hibernate.annotations.FETCH_SIZE 它的获取大小,它没有限制,不是最大结果。冬眠不能
      【解决方案8】:

      如果您的课程 @Repository 扩展了 JpaRepository 您可以使用下面的示例。

      int limited = 100;
      Pageable pageable = new PageRequest(0,limited);
      Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
      return transactionsPage.getContent();
      

      getContent 返回一个List&lt;Transaction&gt;

      【讨论】:

      • 如果我在查询中有 2 个 where 条件,例如 transactionRepository.findByFirstNameAndLastName(firstname, lastname) 怎么办?它会起作用吗?我收到此异常 org.springframework.data.mapping.PropertyReferenceException: No property create found for type Board.
      猜你喜欢
      • 2019-01-21
      • 2019-03-10
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 1970-01-01
      相关资源
      最近更新 更多