使用Spring-Data-JPA进行数据分页与排序

34次阅读

共计 3100 个字符,预计需要花费 8 分钟才能阅读完成。

一、导读

如果一次性加载成千上万的列表数据,在网页上显示将十分的耗时,用户体验不好。所以处理较大数据查询结果展现的时候,分页查询是必不可少的。分页查询必然伴随着一定的排序规则,否则分页数据的状态很难控制,导致用户可能在不同的页看到同一条数据。那么,本文的主要内容就是给大家介绍一下,如何使用 Spring Data JPA 进行分页与排序。

二、实体定义

我们使用一个简单的实体定义:Article(文章)

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name="article")
public class Article {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false,length = 32)
    private String author;

    @Column(nullable = false, unique = true,length = 32)
    private String title;

    @Column(length = 512)
    private String content;

    private Date createTime;
}
  • @Entity 表示这个类是一个实体类,接受 JPA 控制管理,对应数据库中的一个表
  • @Table 指定这个类对应数据库中的表名。如果这个类名和数据库表名符合驼峰及下划线规则,可以省略这个注解。如 FlowType 类名对应表名 flow_type。
  • @Id 指定这个字段为表的主键
  • @GeneratedValue(strategy=GenerationType.IDENTITY) 指定主键的生成方式,一般主键为自增的话,就采用 GenerationType.IDENTITY 的生成方式
  • @Column 注解针对一个字段,对应表中的一列。nullable = false 表示数据库字段不能为空, unique = true 表示数据库字段不能有重复值,length = 32 表示数据库字段最大程度为 32.
  • @Data、@AllArgsConstructor、@NoArgsConstructor、@Builder 都是插件 lombok 的注解,用来帮助我们生成 set、get 方法、构造函数等实体类的模板代码。

三、Repository 定义

定义一个接口 ArticleRepository 继承 PagingAndSortingRepository。PagingAndSortingRepository 接口不仅包含基础的 CURD 函数,还支持排序、分页的接口函数定义。

public interface ArticleRepository extends PagingAndSortingRepository<Article,Long> {
     // 查询 article 表的所有数据,传入 Pageable 分页参数,不需要自己写 SQL
    Page<Article> findAll(Pageable pageable);
    // 根据 author 字段查询 article 表数据,传入 Pageable 分页参数,不需要自己写 SQL
    Page<Article> findByAuthor(String author, Pageable pageable);
    // 根据 author 字段和 title 字段,查询 article 表数据,传入 Pageable 分页参数,不需要自己写 SQL
    Slice<Article> findByAuthorAndTitle(String author, String title, Pageable pageable);
}

四、实现分页

 Pageable 是 Spring 定义的接口,用于分页参数的传递,我们看看如何使用它。首先将 ArticleRepository 注入到你需要进行持久层操作的类里面,通常是一个 @Service 注解的类,然后在服务方法内使用如下代码进行分页操作:查询第一页 (从 0 开始) 的数据,每页 10 条数据。

Pageable pageable = PageRequest.of(0, 10);   // 第一页
//Pageable pageable = PageRequest.of(0, 10);  // 第二页
//Pageable pageable = PageRequest.of(0, 10);  // 第三页
// 数据库操作获取查询结果
Page<Article> articlePage = articleRepository.findAll(pageable);
// 将查询结果转换为 List
List<Article> articleList = articlePage.getContent();

findAll 方法以 Page 类的对象作为响应,如果我们想获取查询结果 List,可以使用 getContent()方法。但是笔者不建议这样进行转换,因为前端展示一个分页列表,不仅需要数据,而且还需要一些分页信息。如:当前第几页,每页多少条,总共多少页,总共多少条。这些信息在 Page(articlePage)对象里面均可以获取到(下文中有介绍)。

五、实现排序

Spring Data JPA 提供了一个 Sort对象,用以提供一种排序机制。让我们看一下排序的方式。


articleRepository.findAll(Sort.by("createTime"));

articleRepository.findAll(Sort.by("author").ascending()
                        .and(Sort.by("createTime").descending()));
  • 第一个 findAll 方法是按照 createTime 的升序进行排序
  • 第一个 findAll 方法是按照 author 的升序排序,再按照 createTime 的降序进行排序

分页和排序在一起

Pageable pageable = PageRequest.of(0, 10,Sort.by("createTime"));

六、Slice 与 Page

在 ArticleRepository 我们看到了一个方法返回 Slice 和另一个方法返回了 Page。它们都是 Spring Data JPA 的数据响应接口,其中 Page 是 Slice 的子接口。它们都用于保存和返回数据。

6.1.Slice

让我们看一下 Slice 的一些重要方法。

List <T>  getContent(); // 获取切片的内容

Pageable  getPageable(); // 当前切片的分页信息

boolean  hasContent(); // 是否有查询结果?boolean  isFirst();  // 是否是第一个切片

boolean  isLast();  // 是否是最后一个切片

Pageable nextPageable(); // 下一个切片的分页信息

Pageable previousPageable(); // 上一个切片的分页信息

6.2.Page

 Page 是 Slice 的子接口,以下是的一些重要方法。

// 总页数
int getTotalPages();

// 总数据条数
long getTotalElements();

那么,什么时候使用 Slice?什么时候使用 Page?
答:通过这两个接口的函数定义可以看出,Slice 只关心是不是存在下一个分片(分页),不会去数据库 count 计算总条数、总页数。所以比较适合大数据量列表的的鼠标或手指滑屏操作,不关心总共有多少页,只关心有没有下一页。Page 比较适合传统应用中的 table 开发,需要知道总页数和总条数。

期待您的关注

  • 博主最近新写了一本书:《手摸手教您学习 SpringBoot 系列 -16 章 97 节》
  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。

正文完
 0