背景
本文是 Spring Data JPA 多条件连表查询 文章的最佳实践总结。
解决什么问题?
使用 Spring Data JPA 需要针对多条件进行连表查询的场景不使用原生 SQL 或者 HQL 的时候,仅仅通过 JpaSpecificationExecutor 构造 Specification 动态条件语句来实现类型安全的多条件查询。
说明
相关上下文背景请前往 前文 了解。这里再提一下接下来示例会用到的场景:
三个实体:作者、书、书评。其中,作者与书是一对多的关系,书与书评是一对一的关系(当然书评与读者的评价是一对多的关系,这里省去,仅用一对一来进行演示即可)。
假设有这样的后台查询条件:作者名称、书的发布时间、书评的评分。(这里每个实体取一个字段进行连表查询演示,其他字段同理)。返回书籍列表以及相关表字段。
【本文所有代码在此】
最佳实践
- 需要 SELECT 查询的字段,通过单独的 Java Bean 进行映射
- 利用 JPA 的自动实体映射结果集
- @EntityGraph 注解标注返回实体需要 Fetch 的字段
- 无需再手动针对连表进行 fetch,解决 N+1 问题
- JOIN ON 查询条件使用 join().on() 拼接
- WHERE 查询条件使用 query.where() 拼接
Join<Object, Object> author = root.join("author"); author.on(cb.equal(author.get("name"), param.getAuthorName()));
query.where(cb.equal(root.get("publishTime"), param.getBookPublishTime()));
代码示例
针对 Repository
- 需要 override 已有 findAll 方法,使用 @EntityGraph 注解
- 使用 @EntityGraph 注解,标注额外属性需要 fetch
// BookJoinRepository.java @Repository public interface BookJoinRepository extends JpaRepository<BookJoin,String>,JpaSpecificationExecutor<BookJoin> { @Override @EntityGraph(attributePaths = { "author", "review" }) Page<BookJoin> findAll(Specification<BookJoin> spec, Pageable pageable); }
针对 Specification
- WHERE 查询条件使用 query.where() 拼接
- JOIN ON 查询条件使用 join().on() 拼接
static Specification<BookJoin> multiQuery_04(BookJoinQuery param) { return (root, query, cb) -> { if (null != param.getBookPublishTime()) { query.where(cb.equal(root.get("publishTime"), param.getBookPublishTime())); } if (null != param.getAuthorName()) { Join<Object, Object> author = root.join("author"); author.on(cb.equal(author.get("name"), param.getAuthorName())); } if (null != param.getReviewScore()) { Join<Object, Object> review = root.join("review"); review.on(cb.equal(review.get("score"), param.getReviewScore())); } return query.getRestriction(); }; }
结果 SQL 语句
select bookjoin0_.id as id1_1_0_, bookjoin_a1_.id as id1_0_1_, bookjoin_r2_.id as id1_2_2_, bookjoin0_.author_id as author_i3_1_0_, bookjoin0_.publish_time as publish_2_1_0_, bookjoin0_.review_id as review_i4_1_0_, bookjoin_a1_.name as name2_0_1_, bookjoin_r2_.score as score2_2_2_ from book bookjoin0_ inner join author bookjoin_a1_ on bookjoin0_.author_id = bookjoin_a1_.id and (bookjoin_a1_.name = ?) inner join review bookjoin_r2_ on bookjoin0_.review_id = bookjoin_r2_.id and (bookjoin_r2_.score = ?) where bookjoin0_.publish_time = ? limit ?
当然,这里案例使用的是 INNER JOIN,对于 LEFT JOIN 也是生效的。
Join<Object, Object> author = root.join("author", JoinType.LEFT); author.on(cb.equal(author.get("name"), param.getAuthorName())); // left outer join author bookjoin_a1_ on // bookjoin0_.author_id = bookjoin_a1_.id // and (bookjoin_a1_.name = ?)
链接
原文地址:https://lexcao.io/zh/posts/spring-data-jpa-join-table-best-practice/
本文链接地址:Spring Data JPA 多条件连表查询最佳实践,英雄不问来路,转载请注明出处,谢谢。
有话想说:那就赶紧去给我留言吧。
文章评论