Spring Data JPA @Query和Pageable

116

我正在使用Spring Data JPA,当我使用@Query来定义一个没有Pageable的查询时,它可以工作:

我使用Spring Data JPA,当我使用@Query定义一个没有Pageable的查询时,它是有效的:

public interface UrnMappingRepository extends JpaRepository<UrnMapping, Long> {
    @Query(value = "select * from internal_uddi where urn like %?1% or contact like %?1%", 
           nativeQuery = true)
    List<UrnMapping> fullTextSearch(String text);
}

但如果我添加第二个参数Pageable@Query将无法工作,Spring将解析方法的名称,然后抛出异常No property full found。这是一个错误吗?

public interface UrnMappingRepository extends JpaRepository<UrnMapping, Long> {
    @Query(value = "select * from internal_uddi where urn like %?1% or contact like %?1%",
           nativeQuery = true)
    Page<UrnMapping> fullTextSearch(String text, Pageable pageable);
}
14个回答

98

您可以使用本地查询进行分页。文档在此处记录:Spring Data JPA - 参考文档

"但是,您可以通过自己指定计数查询来使用本地查询进行分页: 示例59. 在查询方法中使用@Query声明本机计数查询以进行分页"

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

1
countQuery 也适用于非本地化查询,其中Spring无法从原始查询中推导出元素数量。 - darefilz
请在Spring Data JPA文档中向下滚动至示例64. 使用@Query在查询方法中声明本机计数查询以进行分页 - Steve
你的解决方案是有效的,但即使结果正确,我仍然遇到了IllegalArgumentException异常。请问您能否检查一下我的问题:https://dev59.com/N8z6oIgBc1ULPQZF15gN - abidinberkay
如果性能至关重要,countQuery 不适合您。它会触发另一个计数查询来实现它。为了避免这样的开销,您可以返回 Slice<T>List<T> - jumping_monkey

45

在Spring论坛上有一个类似的问题被提出,其中指出为了应用分页,必须派生第二个子查询。由于子查询引用相同的字段,您需要确保查询使用实体/表的别名。这意味着您曾经写过:

select * from internal_uddi where urn like
你应该选择以下内容:
select * from internal_uddi iu where iu.urn like ...

很遗憾,这不能与本地查询一起使用。你知道是否可能通过本地查询实现吗? - vtor
18
如果你想编写本地查询,那么显然需要自己编写用于分页的查询。 - Steve

14

考虑到UrnMapping类映射到internal_uddi表,我建议这样做:

@Repository
public interface UrnMappingRepository extends JpaRepository<UrnMapping, Long> {

    @Query(value = "select iu from UrnMapping iu where iu.urn like %:text% or iu.contact like %:text%")
    Page<UrnMapping> fullTextSearch(@Param("text") String text, Pageable pageable);
}
请注意,您可能需要关闭动态请求中的本机查询。

14

使用 @Query ,我们可以进行分页,其中需要在 JPA 方法的结尾处传递 Pageable 类的对象。

例如:

Pageable pageableRequest = new PageRequest(page, size, Sort.Direction.DESC, rollNo);

其中,page = 页面索引(索引从零开始)
size = 记录数
Sort.Direction = 按rollNo字段排序
rollNo = User类中的字段

UserRepository repo
repo.findByFirstname("John", pageableRequest);

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USER WHERE FIRSTNAME = :firstname)
  Page<User> findByLastname(@Param("firstname") String firstname, Pageable pageable);
}

他在询问原生查询。 - undefined

6
请参考以下示例:

如果您正在使用Spring Data JPA 2.0.4及更高版本,请参考Spring Data JPA @Query。示例如下:

@Query(value = "SELECT u FROM User u ORDER BY id")
Page<User> findAllUsersWithPagination(Pageable pageable);


2

使用@Query在查询方法中声明原生计数查询以实现分页。

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
  countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
  nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);

}

希望这能有所帮助

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods


2
我发现在不同的JPA版本中,其工作方式有所不同。为了调试,您最好添加以下配置以显示生成的SQL语句,这将大大节省您的时间!
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

对于Spring Boot 2.1.6.RELEASE,它运行良好!
Sort sort = new Sort(Sort.Direction.DESC, "column_name");
int pageNumber = 3, pageSize = 5;
Pageable pageable = PageRequest.of(pageNumber - 1, pageSize, sort);

@Query(value = "select * from integrity_score_view " +
        "where (?1 is null or data_hour >= ?1 ) " +
        "and (?2 is null or data_hour <= ?2 ) " +
        "and (?3 is null or ?3 = '' or park_no = ?3 ) " +
        "group by park_name, data_hour ",
        countQuery = "select count(*) from integrity_score_view " +
                "where (?1 is null or data_hour >= ?1 ) " +
                "and (?2 is null or data_hour <= ?2 ) " +
                "and (?3 is null or ?3 = '' or park_no = ?3 ) " +
                "group by park_name, data_hour",
        nativeQuery = true
)
Page<IntegrityScoreView> queryParkView(Date from, Date to, String parkNo, Pageable pageable);

不需要编写order bylimit,它会生成正确的SQL。


1
使用具有 (nativeQuery = true) 的 nativeQuery 时,您可以通过在查询中添加 (LIMIT :sizeValue OFFSET :page) 自己完成分页。
注意: 传递给此方法的页面值应为 offset * size。
示例
 @Query(value = "SELECT * FROM person " +    
                   "LIMIT ?1 OFFSET ?2", nativeQuery = true)
    Optional<List<TDriverJob>> findPersons(int size, int page);

避免使用 Optional<List<T>>,直接使用 List<T>。对于列表(以及集合),已经有一种明确的表示“无结果”的方式,那就是一个空集合。 - jumping_monkey

1
我遇到了同样的问题——没有Pageable方法能正常工作。
当作为方法参数添加时,就无法正常工作了。
在使用数据库控制台和本地查询支持进行尝试后,我得出结论:该方法按照应有的方式工作。但是,只对大写字母有效。
我的应用程序逻辑是实体的所有名称都以大写字母开头。
稍微调整一下它,发现在方法名中加入IgnoreCase就可以"奇迹般"地解决问题,这是可行的解决方案:
public interface EmployeeRepository 
                            extends PagingAndSortingRepository<Employee, Integer> {

    Page<Employee> findAllByNameIgnoreCaseStartsWith(String name, Pageable pageable);

}

实体的样子如下:

@Data
@Entity
@Table(name = "tblEmployees")
public class Employee {

    @Id
    @Column(name = "empID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotEmpty
    @Size(min = 2, max = 20)
    @Column(name = "empName", length = 25)
    private String name;

    @Column(name = "empActive")
    private Boolean active;

    @ManyToOne
    @JoinColumn(name = "emp_dpID")
    private Department department;
}

我该如何做到这一点,但是我有一个视图而不是实体。我想查询视图,但不想编写本地SQL,因为LIKE参数未转义(带有%、~*等)。 - TheRealChx101

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接