springdatajpa高级使用 (springdatajpa完整实例)

想象一下拥有一个可以自动检测 JPA 和 Hibernate 性能问题的工具。那不是太棒了吗?

好吧,Hypersistence Optimizer就是那个工具!它适用于 Spring Boot、Spring Framework、Jakarta EE、Java EE、Quarkus 或 Play Framework。

所以,享受把时间花在自己喜欢的事情上,而不是在周六晚上解决生产系统中的性能问题!

在本文中,我们将探讨在将多个谓词与结果集排序逻辑组合时使用 Spring Data JPA 规范的最佳方式。

虽然您也可以使用查询方法或 @Query注解来定义您的 Spring Data 查询,但 Spring Data JPA 规范允许您动态组合各种过滤条件,这在您可能会非常方便,否则最终会有很多查询方法排列。

域模型和存储库

假设我们 PostComment在应用程序中使用以下实体:

springdatajpa,总结下springdatajpa的常用语法

对于这个实体,我们创建了 PostCommentRepository扩展两个接口的:

  • 来自 BaseJpaRepositoryHypersistence Utils 项目,它是JpaRepositorySpring Data默认值的更好替代方案
  • the JpaSpecificationExecutor, 它提供了 Spring DataSpecification过滤方法
Repository
public interface PostCommentRepository
extends BaseJpaRepository<PostComment, Long>,
JpaSpecificationExecutor<PostComment> {
interface Specs {
static Specification<PostComment> byPost(Post post) {
return (root, query, builder) ->
builder.equal(root.get(PostComment_.post), post);
}
static Specification<PostComment> byStatus(PostComment.Status status) {
return (root, query, builder) ->
builder.equal(root.get(PostComment_.status), status);
}
static Specification<PostComment> byReviewLike(String reviewPattern) {
return (root, query, builder) ->
builder.like(root.get(PostComment_.review), reviewPattern);
}
static Specification<PostComment> byVotesGreaterThanEqual(int votes) {
return (root, query, builder) ->
builder.greaterThanOrEqualTo(root.get(PostComment_.votes), votes);
}
static Specification<PostComment> orderByCreatedOn(
Specification<PostComment> spec) {
return (root, query, builder) -> {
query.orderBy(builder.asc(root.get(PostComment_.createdOn)));
return spec.toPredicate(root, query, builder);
};
}
}
}

请注意,我们有一个 Specs接口,我们在其中定义了几个Specification定义:

过滤 byPost SpecificationPostComment提供的Post实体参考相匹配的实体:

static Specification<PostComment> byPost(Post post) {
return (root, query, builder) ->
builder.equal(root.get(PostComment_.POST), post);
}

请注意,我们正在使用 PostComment_JPA 元模型来引用我们正在匹配的实体属性。

有关生成和使用 JPA 元模型的最佳方式的更多详细信息,请查看这篇文章。

过滤具有提供的 byStatus Specification实体:PostCommentStatus

static Specification<PostComment> byStatus(PostComment.Status status) {
return (root, query, builder) ->
builder.equal(root.get(PostComment_.status), status);
}

过滤具有与提供的模式类似的属性的 byReviewLike Specification实体:PostCommentreview

static Specification<PostComment> byReviewLike(String reviewPattern) {
return (root, query, builder) ->
builder.like(root.get(PostComment_.review), reviewPattern);
}

过滤属性大于或等于提供的投票计数的 byVotesGreaterThanEqual Specification实体:PostCommentvotes

static Specification<PostComment> byVotesGreaterThanEqual(int votes) {
return (root, query, builder) ->
builder.greaterThanOrEqualTo(root.get(PostComment_.votes), votes);
}

orderByCreatedOn Specification向您展示了如何自定义将由 Spring Data JPA 执行的 Criteria API 查询。在这种情况下,我们将传递一个现有的Specification,并将 ORDER BY 逻辑应用于现有查询:

static Specification<PostComment> orderByCreatedOn(
Specification<PostComment> spec) {
return (root, query, builder) -> {
query.orderBy(builder.asc(root.get(PostComment_.createdOn)));
return spec.toPredicate(root, query, builder);
};
}

测试时间

要查找 PostComment属于给定父Post实体的所有实体,我们可以使用byPost Specification

List<PostComment> comments = postCommentRepository.findAll(
byPost(post)
);

Hibernate 将执行以下 SQL 查询:

SELECT
p1_0.id,
p1_0.created_on,
p1_0.parent_id,
p1_0.post_id,
p1_0.review,
p1_0.status,
p1_0.votes
FROM
post_comment p1_0
WHERE
p1_0.post_id = 1

将 ORDER BY 子句添加到 Spring Data JPA 规范

如果我们想在前面的 SQL 查询中添加一个 ORDER BY 子句,我们可以这样做:

List<PostComment> comments = postCommentRepository.findAll(
orderByCreatedOn(
byPost(post)
)
);

请注意,我们将 传递 byPost Specification给 以便orderByCreatedOn当 Spring Data JPA 运行查询时,我们有机会添加 ORDER BY 逻辑,如执行的 SQL 查询所示:

SELECT
p1_0.id,
p1_0.created_on,
p1_0.parent_id,
p1_0.post_id,
p1_0.review,
p1_0.status,
p1_0.votes
FROM
post_comment p1_0
WHERE
p1_0.post_id = 1
ORDER BY
p1_0.created_on ASC

组合多个 Spring Data JPA 规范

Spring Data JPA 规范的最大好处是我们可以根据业务用例的需求组合尽可能多的 Spring Data JPA 规范。

例如,如果我们想要获得所有与 PostComment给定匹配的实体Post,具有Pending状态,具有给定review模式并且投票数大于或等于提供的阈值,我们可以按如下方式编写查询:

List<PostComment> comments = postCommentRepository.findAll(
orderByCreatedOn(
byPost(post)
.and(byStatus(PostComment.Status.PENDING))
.and(byReviewLike(reviewPattern))
.and(byVotesGreaterThanEqual(minVotes))
)
);

Hibernate 将生成以下 SQL 查询:

SELECT
p1_0.id,
p1_0.created_on,
p1_0.parent_id,
p1_0.post_id,
p1_0.review,
p1_0.status,
p1_0.votes
FROM
post_comment p1_0
WHERE
p1_0.post_id = 1 AND
p1_0.status = 0 AND
p1_0.review like 'Awesome%' ESCAPE '' AND
p1_0.votes >= 1
ORDER BY
p1_0.created_on ASC

很酷,对吧?