Jpa之Specifications动态查询
Specifications动态查询
有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。
JpaSpecificationExecutor接口
JpaSpecificationExecutor接口中定义的方法:
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
public interface JpaSpecificationExecutor<T> {
//根据条件查询一个对象
Optional<T> findOne(@Nullable Specification<T> var1);
//根据条件查询对象集合
List<T> findAll(@Nullable Specification<T> var1);
//根据条件查询并进行分页
//pageable :分页参数
//返回值:分页pageBean,由springdatajpa提供
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
//排序查询查询
// Sort:排序参数
List<T> findAll(@Nullable Specification<T> var1, Sort var2);
//统计查询
long count(@Nullable Specification<T> var1);
}
//备注
// 如果可以传入NULL值,则标记为@Nullable,如果不可以,则标注为@Nonnull。
对于JpaSpecificationExecutor,我们可以发现这个接口方法基本是围绕着Specification接口来定义的。我们可以简单的理解为,Specification构造的就是查询条件。
——>我们需要自定义我们自己的Specification实现类。
Specfication接口
在Specification接口中只定义了如下一个方法:
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
//root:查询的根对象(查询的任何属性都可以从根对象中获取)
//CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
//CriteriaBuilder:查询的构造器,用来构建查询条件,此对象里封装了很多查询条件方法
public interface Specification<T> {
Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}
方法对应关系
方法 | SQL对应语法 |
---|---|
equle | filed = value |
gt(greaterThan ) | filed > value |
lt(lessThan) | filed < value |
ge(greaterThanOrEqualTo ) | filed >= value |
le( lessThanOrEqualTo) | filed <= value |
notEqule | filed != value |
like | filed like value |
notLike | filed not like value |
and | 条件1 and 条件2 and 条件3…and 条件n |
or | 条件1 or 条件2 or 条件3…or 条件n |
示例
/**自定义动态查询
* (1)实例化Specification接口
* ——重写toPredicate方法
* * root:获取需要查询的对象属性
* *CriteriaBuilder:构建查询条件的,内部封装了很多的查询条件(模糊查询,精准匹配)
* (2)调用JpaSpecificationExecutor接口方法查询
* (3)查询结果使用
*/
示例1,equal 精确查询
@Test
public void testSpec01(){
//(1)实现Specification接口
Specification<Student> spec = new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//1.获取比较的属性
Path<Object> name = root.get("stuName");
//2.构造查询条件
Predicate predicate = criteriaBuilder.equal(name, "赵云");
return predicate;
}
};
//(2)调用JpaSpecificationExecutor接口方法查询
Optional<Student> optional = repository.findOne(spec);
// (3)查询结果使用
if (optional.isPresent()){
System.out.println("查询出结果:"+optional.get());
}else {
System.out.println("没有查询出结果!!!");
}
}
示例2,like 模糊查询
/**
* like 模糊查询
*/
@Test
public void testSpec2(){
Specification<Student> spec =new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> name = root.get("stuName");
Predicate predicate = criteriaBuilder.like(name.as(String.class), "%赵%");
return predicate;
}
};
List<Student> students = repository.findAll(spec);
students.forEach(a->System.out.println(a.toString()));
}
示例3,组合and查询
/**
* 组合查询
*/
@Test
public void testSpec3(){
Specification<Student> spec =new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> name = root.get("stuName");
Path<Object> age = root.get("age");
Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
Predicate predicate02 = criteriaBuilder.equal(name,"赵云");
Predicate predicate = criteriaBuilder.and(predicate01, predicate02);
return predicate;
}
};
List<Student> students = repository.findAll(spec);
students.forEach(a->System.out.println(a.toString()));
}
示例4,组合or查询
/**
* 组合or查询
*/
@Test
public void testSpec4(){
Specification<Student> spec =new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> name = root.get("stuName");
Path<Object> age = root.get("age");
Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
Predicate predicate02 = criteriaBuilder.equal(name,"赵云");
Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
return predicate;
}
};
List<Student> students = repository.findAll(spec);
students.forEach(a->System.out.println(a.toString()));
}
示例5,查询排序
/**
* 查询排序
*/
@Test
public void testSpec5(){
Sort sort =new Sort(Sort.Direction.ASC,"age");
Specification<Student> spec =new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> name = root.get("stuName");
Path<Object> age = root.get("age");
Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
Predicate predicate02 = criteriaBuilder.equal(name,"赵云");
Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
return predicate;
}
};
List<Student> students = repository.findAll(spec,sort);
students.forEach(a->System.out.println(a.toString()));
}
示例6,查询分页
/**
* 查询分页
*/
@Test
public void testSpec6(){
Sort sort =new Sort(Sort.Direction.ASC,"age");
PageRequest pageRequest = PageRequest.of(1,2,sort);
Specification<Student> spec =new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> name = root.get("stuName");
Path<Object> age = root.get("age");
Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
Predicate predicate02 = criteriaBuilder.equal(name,"赵云");
Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
return predicate;
}
};
Page<Student> studentPage = repository.findAll(spec, pageRequest);
long totalElements = studentPage.getTotalElements();//获取全部数量
System.out.println("供查询数据量:"+totalElements);
int totalPages = studentPage.getTotalPages();//获取全部页数
System.out.println("供查询数据页数:"+totalElements);
List<Student> students = studentPage.getContent();//获取全部内容
students.forEach(a->System.out.println(a.toString()));
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~