SpringDataJpa的使用 -- 条件查询、排序查询、分页查询
SpringDataJpa的使用 -- 条件查询、排序查询、分页查询、分组查询、统计查询
SpringDataJpa的使用 – 条件查询、排序查询、分页查询
本文以 Article.java 为数据存放类,操作接口为 ArticleRepository.java
@Data
lombok 的注解,用来生成 Getter、Setter、toString、hashCode 方法,当添加该注解的同时在添加 相应方法(如 toString())时,添加的方法不会被覆盖。
@NoArgsConstructor
lombok 的注解,用来生成 无参构造函数。
@AllArgsConstructor
lombok 的注解,用来生成 全参构造函数。
@JsonIgnore
用来破坏实体类序列化时,产生的无限递归循环。
在本次的测试中,还需要 重写 Author.java 的 toString 方法,目的是这两个类中必须有一方的 toString 方法没有外键属性,可以双方都没有。
Author.java
/**
* 作者 类
*
* @author LJM
*/
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "AUTHOR")
public class Author {
/**
* 作者 id
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "author_id", nullable = false)
private Long authorId;
/**
* 作者 姓名
*/
@Column(name = "author_Name", nullable = false)
private String authorName;
/**
* 作者 简介
*/
@Column(name = "author_referral", nullable = false)
private String authorReferral;
/**
* 一对多
* 一方
* (被)维护方
*
* 文章列表
*/
@JsonIgnore
@OneToMany(mappedBy = "author", fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.REMOVE})
private List<Article> articleList;
@Override
public String toString() {
return "Author{" +
"authorId=" + authorId +
", authorName='" + authorName + '\'' +
", authorReferral='" + authorReferral + '\'' +
'}';
}
}
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", nullable = false)
private String articleTitle;
/**
* 文章 内容
*/
@Column(name = "article_content", nullable = false)
private String articleContent;
/**
* 文章 类型
*/
@Column(name = "article_type", nullable = false)
private String articleType;
/**
* 文章 阅读量
*/
@Column(name = "article_read_number", nullable = false)
private Integer articleReadNumber;
/**
* 文章 点赞数
*/
@Column(name = "article_likes_number", nullable = false)
private Integer articleLikesNumber;
/**
* 多对一
* 多方
* 作者外键
* 维护方
*/
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "article_author_id", nullable = false)
private Author author;
}
ArticleRepository.java 这只是最基础的内容,会后续添加 接口或方法 来增加功能。
public interface ArticleRepository extends JpaRepository<Article, Long> {
}
排序查询
法 一
使用 JpaRepository 的 List findAll(Sort sort)
方法,无需添加新的 方法或接口。
-
Sort.by(String) 方法的参数是 字符串数组,可以添加一到多个类属性名来排序。
-
ascending 方法表示升序排序(默认就是),写法:Sort.by(String).ascending()。
-
descending 方法表示降序排序,写法:Sort.by(String).descending()。
-
根据多个类属性来排序时,是在不破坏前一个的排序结果的基础上对后一个进行排序,以此类推。
@Test
public void test1(){
List<Article> articleList=articleRepository.findAll(Sort.by("articleType").ascending());
System.out.println("====== 升序(类型) ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
List<Article> articleList1=articleRepository.findAll(Sort.by("articleType","articleReadNumber").ascending());
System.out.println("====== 升序(类型)(阅读量) ======");
articleList1.stream().map(Objects::toString).forEach(System.out::println);
}
- 如果 输入的类属性不存在就会报错,故需要:
检验输入的类属性是否存在
@Test
public void test2(){
List<Article> articleList=articleRepository.findAll(Sort.by("articleType1").ascending());
System.out.println("====== 升序(类型) ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
}
org.springframework.data.mapping.PropertyReferenceException: No property 'articleType1' found for type 'Article'! Did you mean ''articleType''?
- 能不能设置按第一个属性升序,再按第二个属性降序呢?答案是:
当然
。
by() 是静态方法,不支持变量调用,每一个 by() 后只能添加一个 排序方法。 但是,Sort 有一个 and(Sort) 方法,用来将两个 Sort 合并,该方法由变量调用,理论上可以无限叠加。
@Test
public void test3(){
List<Article> articleList=articleRepository.findAll(Sort.by("articleType","articleReadNumber").ascending());
System.out.println("====== 升序(类型)(阅读量) ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
Sort sort=Sort.by("articleType").ascending();
sort=sort.and(Sort.by("articleReadNumber").descending());
List<Article> articleList1=articleRepository.findAll(sort);
System.out.println("====== 类型升序、再阅读量降序 ======");
articleList1.stream().map(Objects::toString).forEach(System.out::println);
}
分页查询
法 一
使用 PagingAndSortingRepository 的 Page findAll(Pageable pageable)
方法,JpaRepository 继承了
PagingAndSortingRepository 接口,无需添加新的 方法或接口。
-
Page 几个常用的属性:
- content 数组 ,存放 List<Object> 的形式的数据。
- pageable 类,与上面的方法的参数一致,存放了数据的总数、当前页数、当前排序属性 等等。
-
用 PageRequest.of([页码],[页大小]) 创建 Pageable 变量,然后填入 Page findAll(Pageable) 方法即可。
@Test
public void test4(){
Pageable pageable=PageRequest.of(0,5);
Page<Article> articleList=articleRepository.findAll(pageable);
System.out.println("====== 分页结果 0,5 ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
Pageable pageable1=PageRequest.of(0,30);
Page<Article> articleList1=articleRepository.findAll(pageable1);
System.out.println("====== 分页结果 0,30 ======");
articleList1.stream().map(Objects::toString).forEach(System.out::println);
}
-
注意:
PageRequest.of(0, 5) 表示 第一页,每页5条
;PageRequest.of(1, 5) 表示 第二页,每页5条
。 -
当页数大于数据条数时,如果是第一页,不报错,查询全部;
如果不是第一页,那么无法执行,即:当前页码的数据必须大于等于一条,才能成功执行
。 我之前测试时,是报错的,现在又可以了。
@Test
public void test5(){
Pageable pageable=PageRequest.of(1,5);
Page<Article> articleList=articleRepository.findAll(pageable);
System.out.println("====== 分页结果 0,5 ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
Pageable pageable2=PageRequest.of(1,10);
Page<Article> articleList2=articleRepository.findAll(pageable2);
System.out.println("====== 分页结果 0,30 ======");
articleList2.stream().map(Objects::toString).forEach(System.out::println);
}
条件查询
法 一
- 使用 JpaRepository 提供的,通过使用关键字来实现的条件查询。功能丰富。
- 如:根据文章类型查询、根据 文章 类型 和 部分文章内容 查询 等等。
/**
* 文章 操作 接口
*
* @author l'j'm
*/
public interface ArticleRepository extends JpaRepository<Article, Long> {
/**
* 根据 文章 类型 查询
*
* @param articleType 文章 类型
*
* @return list
*/
List<Article> findByArticleType(String articleType);
/**
* 根据 文章 类型 查询
*
* @param articleType 文章 类型
*
* @return list
*/
List<Article> findAllByArticleType(String articleType);
/**
* 根据 文章 类型 和 部分文章内容 查询
*
* @param articleType 文章 类型
* @param articleContent 文章内容
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent);
}
-
Jpa 支持的关键字中,已经描述的很详细了,不再重复描述。
-
标准的写法是以 findBy 开头的,当然 findAllBy 开头的结果是一样,但不建议。
@Test
public void aVoid1(){
List<Article> articleList=articleRepository.findByArticleType("后端");
List<Article> articleList1=articleRepository.findAllByArticleType("后端");
System.out.println("====== 默认 ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 默认(All) ======");
articleList1.stream().map(Objects::toString).forEach(System.out::println);
}
@Test
public void aVoid2(){
List<Article> articleList=articleRepository.findByArticleType("后端");
List<Article> articleList2=articleRepository
.findByArticleType("后端",Sort.by("articleReadNumber").ascending());
List<Article> articleList3=articleRepository
.findByArticleTypeAndArticleContentLike("后端","%好%");
System.out.println("====== 默认 ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 查询,升序(阅读量) ======");
articleList2.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======");
articleList3.stream().map(Objects::toString).forEach(System.out::println);
}
组合
- 是指,三种不同的查询分类 两两结合 或 三个成组 地使用,可以适应比较复杂的查询。
条件
+ 排序
法 一
-
在 根据关键字实现的 接口方法中添加参数 Sort 就可以添加排序条件。
-
注意:
方法名不能改
,即 想要添加 排序,只需添加添加参数 Sort,不能改方法名。 -
为什么可以这样写呢?
-
因为,添加关键字来实现 条件查询,实现时是在内部解析 方法名,然后构建 SQL 语句,最后剩下 findAll(Sort) ,而该方法是有对应的解析方法的。
/**
* 文章 操作 接口
*
* @author l'j'm
*/
public interface ArticleRepository extends JpaRepository<Article, Long> {
/**
* 根据 文章 类型 查询
*
* @param articleType 文章 类型
*
* @return list
*/
List<Article> findByArticleType(String articleType);
/**
* 根据 文章 类型 查询 并排序
*
* @param articleType 文章 类型
* @param sort 排序条件
*
* @return list
*/
List<Article> findByArticleType(String articleType, Sort sort);
/**
* 根据 文章 类型 和 部分文章内容 查询
*
* @param articleType 文章 类型
* @param articleContent 文章内容
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent);
/**
* 根据 文章 类型 和 部分文章内容 查询 并排序
*
* @param articleType 文章 类型
* @param articleContent 文章内容
* @param sort 排序条件
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Sort sort);
}
- 测试
@Test
public void aVoid2(){
List<Article> articleList=articleRepository.findByArticleType("后端");
List<Article> articleList2=articleRepository
.findByArticleType("后端",Sort.by("articleReadNumber").ascending());
List<Article> articleList3=articleRepository
.findByArticleTypeAndArticleContentLike("后端","%好%");
List<Article> articleList4=articleRepository
.findByArticleTypeAndArticleContentLike("后端","%好%",Sort.by("articleReadNumber").ascending());
System.out.println("====== 默认 ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 查询,升序(阅读量) ======");
articleList2.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======");
articleList3.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 和 部分文章内容 查询,升序(阅读量) ======");
articleList4.stream().map(Objects::toString).forEach(System.out::println);
}
条件
+ 分页
法 一
-
在 根据关键字实现的 接口方法中添加参数 Pageable 就可以添加 分页条件。
-
注意:
方法名不能改
,即 想要添加 分页,只需添加添加参数 Pageable,不能改方法名。 -
为什么可以这样写呢?
-
因为,添加关键字来实现 条件查询时,实现是在内部解析 方法名,然后构建 SQL 语句,最后剩下 findAll(Pageable) ,而该方法是有对应的解析方法的。
/**
* 文章 操作 接口
*
* @author l'j'm
*/
public interface ArticleRepository extends JpaRepository<Article, Long> {
/**
* 根据 文章 类型 查询
*
* @param articleType 文章 类型
*
* @return list
*/
List<Article> findByArticleType(String articleType);
/**
* 根据 文章 类型 查询 并 分页
*
* @param articleType 文章 类型
* @param pageable 分页条件
*
* @return list
*/
List<Article> findByArticleType(String articleType, Pageable pageable);
/**
* 根据 文章 类型 和 部分文章内容 查询
*
* @param articleType 文章 类型
* @param articleContent 文章内容
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent);
/**
* 根据 文章 类型 和 部分文章内容 查询 并 分页
*
* @param articleType 文章 类型
* @param articleContent 文章内容
* @param pageable 分页条件
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Pageable pageable);
}
- 测试
@Test
public void aVoid3(){
List<Article> articleList=articleRepository.findByArticleType("后端");
List<Article> articleList2=articleRepository
.findByArticleType("后端",PageRequest.of(0,2));
List<Article> articleList3=articleRepository
.findByArticleTypeAndArticleContentLike("后端","%好%");
List<Article> articleList4=articleRepository
.findByArticleTypeAndArticleContentLike("后端","%好%",PageRequest.of(1,1));
System.out.println("====== 默认 ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 查询,分页(0,2) ======");
articleList2.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======");
articleList3.stream().map(Objects::toString).forEach(System.out::println);
System.out.println("====== 根据 文章 类型 和 部分文章内容 查询,分页(1,1) ======");
articleList4.stream().map(Objects::toString).forEach(System.out::println);
}
分页
+ 排序
法 一
-
Pageable 类中有参数 Sort,只需 将配置好的 Sort 传入 Pageable 中即可
-
其他的 使用方法,与前文无异。
@Test
public void void1(){
Sort sort=Sort.by("articleType").ascending();
List<Article> articleList=articleRepository.findAll(sort);
System.out.println("====== 升序(类型) ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
Pageable pageable=PageRequest.of(1,5);
Page<Article> articleList1=articleRepository.findAll(pageable);
System.out.println("====== 分页结果 0,5 ======");
articleList1.stream().map(Objects::toString).forEach(System.out::println);
// Pageable pageable1 = PageRequest.of(1, 5).withSort(sort);
Pageable pageable1=PageRequest.of(1,5,sort);
Page<Article> articleList2=articleRepository.findAll(pageable1);
System.out.println("====== 分页结果 0,5 ======");
articleList2.stream().map(Objects::toString).forEach(System.out::println);
}
条件
+ 分页
+ 排序
-
注意 踩坑
:没有 findBy…And…(String…, Pageable, Sort) 这种写法的。 -
原因
:没有 findAll(Pageable, Sort) 这个基方法。 -
findByArticleType(String, Pageable) 和 findByArticleType(String, Sort) 可以执行,是因为有 findAll(Pageable),findAll(Sort)
这两个基方法。
法 一
看了前文你应该猜到了,没错,就是 用关键字实现条件查询
,再添加 带有排序的分页参数
实现。
- 写法 是:findBy…And…(String…, Pageable),直接套用
条件 + 分页
方法即可
/**
* 文章 操作 接口
*
* @author l'j'm
*/
public interface ArticleRepository extends JpaRepository<Article, Long> {
/**
* 根据 文章 类型 查询
*
* @param articleType 文章 类型
*
* @return list
*/
List<Article> findByArticleType(String articleType);
/**
* 根据 文章 类型 查询 并 分页
*
* @param articleType 文章 类型
* @param pageable 分页条件
*
* @return list
*/
List<Article> findByArticleType(String articleType, Pageable pageable);
/**
* 根据 文章 类型 和 部分文章内容 查询
*
* @param articleType 文章 类型
* @param articleContent 文章内容
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent);
/**
* 根据 文章 类型 和 部分文章内容 查询 并 分页
*
* @param articleType 文章 类型
* @param articleContent 文章内容
* @param pageable 分页条件
*
* @return list
*/
List<Article> findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Pageable pageable);
}
- 测试
@Test
public void void2(){
Sort sort=Sort.by("articleReadNumber").descending();
Pageable pageable=PageRequest.of(0,5);
// Pageable pageable1 = PageRequest.of(0, 5).withSort(sort);
Pageable pageable1=PageRequest.of(0,5,sort);
List<Article> articleList=articleRepository.findByArticleType("后端",pageable);
System.out.println("====== 后端,分页结果 (0,5) ======");
articleList.stream().map(Objects::toString).forEach(System.out::println);
List<Article> articleList2=articleRepository.findByArticleType("后端",pageable1);
System.out.println("====== 后端,分页结果 (0,5),排序 ======");
articleList2.stream().map(Objects::toString).forEach(System.out::println);
}
关于 分组查询 和 统计查询
下篇更新。
(首发)如果对你有帮助,点赞可好!!
更多推荐
所有评论(0)