SpringDataJpa的使用 -- 条件查询、排序查询、分页查询 二

813 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

SpringDataJpa的使用 -- 条件查询、排序查询、分页查询 二

上一篇文章:SpringDataJpa的使用 -- 条件查询、排序查询、分页查询 - 掘金 (juejin.cn)

本文在前文的基础上补充了 条件查询、分组查询、统计查询 的其他实现方法。

同时,添加了前文所没有的 指定查询属性 ,其他的方法基本都是查询全部字段的。

实体类不变,nullable = false 不是必须的;Repository 接口 大体一致。

Article.java

/**
 * 文章 类
 *
 * @author LJM
 */
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "ARTICLE")
public class Article {
	/**
	 * 文章 id
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "article_id", nullable = false)
	private Long articleId;
	/**
	 * 文章 标题
	 */
	@Column(name = "article_title")
	private String articleTitle;
	/**
	 * 文章 内容
	 */
	@Column(name = "article_content")
	private String articleContent;
	/**
	 * 文章 类型
	 */
	@Column(name = "article_type")
	private String articleType;
	/**
	 * 文章 阅读量
	 */
	@Column(name = "article_read_number")
	private Integer articleReadNumber;
	/**
	 * 文章 点赞数
	 */
	@Column(name = "article_likes_number")
	private Integer articleLikesNumber;
	/**
	 * 多对一
	 * 多方
	 * 作者外键
	 * 维护方
	 */
	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "article_author_id")
	private Author author;
	/**
     * 省略了其他的 构造函数
	 */
}

ArticleRepository.java

/**
 * 文章 操作 接口
 *
 * @author l'j'm
 */
public interface ArticleRepository extends JpaRepository<Article, Long>, JpaSpecificationExecutor<Article> {
}

再继承了一个和 JpaRepository 同包的接口 JpaSpecificationExecutor,

须知

本文引入新接口和方法,需要先行简述所需要的参数,方便阅读。

entityManager,用于与持久化上下文交互的接口。

  • 其中对于任何持久性实体身份都有一个唯一的实体实例。就是说,每一次 数据持久化操作都有一个唯一的 entityManager 来完成该功能。

  • 在持久性上下文中,entityManager 管理实体实例及其生命周期。

  • 在 Spring Boot 中 通过 @Resource 即可获取。

@Resource
private EntityManager entityManager;

CriteriaBuilder,是一个泛型,可以理解为:构建条件查询 HQL 语句的构造器。

下面是获得该类对象的方法,其中 entityManager 是前面提到的 持久化管理对象。

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

CriteriaQuery,是一个泛型,可以理解为:添加条件查询构建好的 HQL 语句。

下面是获得该类对象的方法,其中 criteriaBuilder 前面获得的 查询条件构造器。

CriteriaQuery<Article> criteriaQuery = criteriaBuilder.createQuery(class);

Specification,是一个泛型,可以理解为存储查询条件的类。

下面是创建该类对象的方法,其中 CriteriaQuery、CriteriaBuilder 就是前面提到的 查询语句和查询构造器,在方法里已经创建好了,不需要我们关心。

Specification<Article> criteriaQueryBuilder = new Specification<Article>() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {
        // 内容
    }
};

Root,是一个泛型,from 子句中的根类型,查询根始终引用实体,可以理解为:用于构建查询条件键值对。

  • 根据属性名在设定好的实体类中找到它,并添加到 查询语句 上。

条件查询

法一在上一篇文章中提到了,是用 JpaRepository 提供的,通过使用关键字来实现的条件查询。

仅条件查询

  • 是继承 JpaSpecificationExecutor 接口,使用 findAll(@Nullable Specification) 方法。

  • 首先创建一个 Specification 对象,再将对象传入 findAll() 中。

@Test
public void aVoid1() {
    Specification<Article> criteriaQueryBuilder = (root, query, criteriaBuilder)
        -> criteriaBuilder.equal(root.get("articleType"), "后端");
    List<Article> articleList = articleRepository.findAll(criteriaQueryBuilder);
    System.out.println("======  后端 ======");
    articleList.stream().map(Objects::toString).forEach(System.out::println);
    
    Specification<Article> criteriaQueryBuilder1 = (root, query, criteriaBuilder) -> {
        Predicate predicate = criteriaBuilder.equal(root.get("articleType"), "后端");
        Predicate predicate1 = criteriaBuilder.like(root.get("articleContent"), "%好%");
        return criteriaBuilder.and(predicate, predicate1);
    };
    List<Article> articleList1 = articleRepository.findAll(criteriaQueryBuilder1);
    System.out.println("======  后端,部分内容 ======");
    articleList1.stream().map(Objects::toString).forEach(System.out::println);
}
  • root 用于构建查询条件键值对;query 用于组装查询语句;criteriaBuilder 用于构建查询语句。

条件查询并排序、分页

  • 同上文一样,JpaSpecificationExecutor 接口的 findAll() 方法还有 findAll(@Nullable Specification, Sort)、findAll(@Nullable Specification, Pageable) 这两种。

  • Sort 是排序条件;Pageable 是分页条件。

  • 需要分页并排序时,将 Sort 放入 Pageable 中,再把 Pageable 传入 findAll() 方法中。

  • 例子

@Test
public void aVoid2() {
    Specification<Article> criteriaQueryBuilder = (root, query, criteriaBuilder)
            -> criteriaBuilder.equal(root.get("articleType"), "后端");
    Pageable pageable1 = PageRequest.of(0, 4);
    Page<Article> articleList = articleRepository.findAll(criteriaQueryBuilder, pageable1);
    System.out.println("======  后端并分页  ======");
    articleList.stream().map(Objects::toString).forEach(System.out::println);
    
    
    Specification<Article> criteriaQueryBuilder1 = (root, query, criteriaBuilder) -> {
        Predicate predicate = criteriaBuilder.equal(root.get("articleType"), "后端");
        Predicate predicate1 = criteriaBuilder.like(root.get("articleContent"), "%好%");
        return criteriaBuilder.and(predicate, predicate1);
    };
    
    Pageable pageable2 = PageRequest.of(0, 4);
    Page<Article> articleList2 = articleRepository.findAll(criteriaQueryBuilder1, pageable2);
    System.out.println("======  后端,部分内容 并排序  ======");
    articleList2.stream().map(Objects::toString).forEach(System.out::println);
    
    Pageable pageable3 = PageRequest.of(0, 4, Sort.by("articleReadNumber").ascending());
    Page<Article> articleList3 = articleRepository.findAll(criteriaQueryBuilder1, pageable3);
    System.out.println("======  后端,部分内容 并分页排序  ======");
    articleList3.stream().map(Objects::toString).forEach(System.out::println);
}
  • 构建出来的 查询语句 是 HQL 语句。

(二发)如果对你有帮助,点赞可好!!