1. 概述
Spring Data Commons 是Spring Data项目的一部分,它包含管理持久层的接口和实现。滚动API是Spring Data Commons提供的功能之一,用于处理从数据库读取的大结果集。
在这个教程中,我们将一起探索滚动API及其示例。
2. 依赖
滚动API在Spring Boot 3.1版本中添加支持。Spring Data Commons已经包含在了Spring Data JPA中。因此,只需添加Spring Data JPA 3.1版本即可获得滚动API的功能:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.1.0</version>
</dependency>
最新的库版本可以在Maven中央仓库找到。
3. 实体类
为了演示目的,我们将使用BookReview
实体,它包含了各个用户对不同书籍的评论评级:
@Entity
@Table(name="BOOK_REVIEWS")
public class BookReview {
@Id
@GeneratedValue(strategy= GenerationType.SEQUENCE, generator = "book_reviews_reviews_id_seq")
@SequenceGenerator(name = "book_reviews_reviews_id_seq", sequenceName = "book_reviews_reviews_id_seq", allocationSize = 1)
private Long reviewsId;
private String userId;
private String isbn;
private String bookRating;
// getters and setters
}
4. 滚动API
滚动API提供了按块迭代大量结果的功能。 它提供稳定的排序、滚动类型和结果限制。
我们可以通过使用属性名称定义简单的排序表达式,并通过查询衍生法使用Top
或First
来定义静态结果限制。
4.1. 使用偏移过滤滚动
下面的示例中,我们使用查询衍生方法,根据评分参数和OffsetScrollPosition
找到前五个书籍:
public interface BookRepository extends Repository<BookReview, Long> {
Window<BookReview> findFirst5ByBookRating(String bookRating, OffsetScrollPosition position);
Window<BookReview> findFirst10ByBookRating(String bookRating, OffsetScrollPosition position);
Window<BookReview> findFirst3ByBookRating(String bookRating, KeysetScrollPosition position);
}
既然我们定义了Repository方法,可以在逻辑类中使用它们来获取前五个书籍并持续迭代,直到达到最后一个结果。
在迭代过程中,我们需要查询是否存在下一个窗口:
public List<BookReview> getBooksUsingOffset(String rating) {
OffsetScrollPosition offset = ScrollPosition.offset();
Window<BookReview> bookReviews = bookRepository.findFirst5ByBookRating(rating, offset);
List<BookReview> bookReviewsResult = new ArrayList<>();
do {
bookReviews.forEach(bookReviewsResult::add);
bookReviews = bookRepository.findFirst5ByBookRating(rating, (OffsetScrollPosition) bookReviews.positionAt(bookReviews.size() - 1));
} while (!bookReviews.isEmpty() && bookReviews.hasNext());
return bookReviewsResult;
}
我们可以简化逻辑,使用WindowIterator
,它提供了无需检查下一个窗口和ScrollPosition
就能浏览大结果的便利工具:
public List<BookReview> getBooksUsingOffSetFilteringAndWindowIterator(String rating) {
WindowIterator<BookReview> bookReviews = WindowIterator.of(position -> bookRepository
.findFirst5ByBookRating("3.5", (OffsetScrollPosition) position)).startingAt(ScrollPosition.offset());
List<BookReview> bookReviewsResult = new ArrayList<>();
bookReviews.forEachRemaining(bookReviewsResult::add);
return bookReviewsResult;
}
基于偏移的滚动工作方式类似于分页,它跳过大量结果中的某些记录返回预期结果。虽然我们只看到请求结果的一部分,但服务器需要构建完整的结果,这会增加额外的负载。
我们可以使用键集过滤来避免这种行为。
4.2. 使用键集过滤滚动
键集过滤利用数据库的内置能力帮助检索子集结果,旨在减少单个查询的计算和IO需求。
数据库只需要根据给定的键集位置构造较小的结果,而不需要materialize整个大结果:
public List<BookReview> getBooksUsingKeySetFiltering(String rating) {
WindowIterator<BookReview> bookReviews = WindowIterator.of(position -> bookRepository
.findFirst5ByBookRating(rating, (KeysetScrollPosition) position))
.startingAt(ScrollPosition.keyset());
List<BookReview> bookReviewsResult = new ArrayList<>();
bookReviews.forEachRemaining(bookReviewsResult::add);
return bookReviewsResult;
}
5. 总结
在这篇文章中,我们探讨了Spring Data Commons库提供的滚动API。滚动API支持基于偏移位置和过滤条件分块读取大结果。
滚动API支持基于偏移和键集的过滤。 基于偏移的过滤需要在数据库中materialize整个结果,而键集则通过构造较小结果来减轻数据库的计算和IO负担。
如往常一样,示例代码可在GitHub上找到。