我们在上一章节已经学习了Spring Boot中使用mysql数据库的读取功能。
Spring Boot中使用mysql数据库
本章节来学习一下使用JPA如何多条件查询mysql。
我们一开始继承的CrudRepository接口支持一些简单的查询,以及在Repository接口中增加一些方法,例如:
List findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
等进行一些字段值查询。
但是当我们想要进行一些比较灵活的多条件查询时,则需要重写一下查询组件。
在使用Spring Data JPA的时候,只要我们的Repo层继承JpaSpecificationExecutor接口就可以使用Specification进行多条件动态查询了,我们先看下JpaSpecificationExecutor接口:
public interface JpaSpecificationExecutor<T> {
T findOne(Specification<T> spec);
List<T> findAll(Specification<T> spec);
Page<T> findAll(Specification<T> spec, Pageable pageable);
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);
}
可以看到提供了5个方法,方法的参数和返回值已经很明显的表达了其意图。其中的参数,Pageable和Sort应该是比较简单的,分别是分页参数和排序参数,而重点就是Specification参数,先看下这个接口的定义:
public interface Specification {
Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb);
}
其中就一个方法,返回的是动态查询的数据结构。
javax.persistence.criteria.Predicate toPredicate(javax.persistence.criteria.Root root,
javax.persistence.criteria.CriteriaQuery> query,
javax.persistence.criteria.CriteriaBuilder cb);
这里使用的都是Java EE中的规范,具体实现本人采用的是Hibernate,当然也可以选择其他实现了JPA规范的数据持久层框架。
这里需要再次回过头看看Criteria API中的一些东西:
Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。
CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用
Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似
1:Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。
2:查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。
3:Criteria查询,可以有多个查询根。
4:AbstractQuery是CriteriaQuery 接口的父类,它提供得到查询根的方法。CriteriaBuilder接口:用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合
其中支持的方法非常之强大,下面给出一个示例,大家可以参考一下,同样的,可以根据示例,自己可以写出更为复杂的查询:
新建实体
我们需要操作的实体字段如下:
package com.biologic.entity;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name= "t_quality_inspection")
public class QualityCheck {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String version;
private Date upload_time;
private int qualified;
private int released;
private int processed;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Date getUpload_time() {
return upload_time;
}
public void setUpload_time(Date upload_time) {
this.upload_time = upload_time;
}
public int getQualified() {
return qualified;
}
public void setQualified(int qualified) {
this.qualified = qualified;
}
public int getReleased() {
return released;
}
public void setReleased(int released) {
this.released = released;
}
public int getProcessed() {
return processed;
}
public void setProcessed(int processed) {
this.processed = processed;
}
}
QualityCheckRepository.java
代码如下:
package com.biologic.api.service;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Service;
import com.biologic.entity.QualityCheck;
@Service
public interface QualityCheckRepository extends JpaRepository, JpaSpecificationExecutor {
}
重写findAll中的new Specification()方法和public Predicate toPredicate(Root root, CriteriaQuery
package com.biologic.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.biologic.api.service.QualityCheckRepository;
import com.biologic.entity.QualityCheck;
@Controller
@RequestMapping(path = "/demo")
public class QualityCheckController {
@Autowired
private QualityCheckRepository qualityCheckRepository;
@GetMapping(path = "/qualityCheck")
public @ResponseBody String qualityCheck() {
QualityCheck model = new QualityCheck();
model.setQualified(1);
model.setProcessed(0);
List results = findSearch(model);
for (QualityCheck qualityCheck : results) {
System.out.println("正在质检:" + qualityCheck.getId());
qualityCheck.setProcessed(1);
qualityCheckRepository.save(qualityCheck);
}
return "ok";
}
public List findSearch(QualityCheck model) {
List result = qualityCheckRepository.findAll(new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
List list = new ArrayList();
list.add(cb.equal(root.get("qualified").as(Integer.class), model.getQualified()));
list.add(cb.equal(root.get("processed").as(Integer.class), model.getProcessed()));
if (model.getVersion() != null && !model.getVersion().equals("")) {
list.add(cb.equal(root.get("version").as(String.class), model.getVersion()));
}
if (model.getVersion() != null && !model.getVersion().equals("")) {
list.add(cb.like(root.get("version").as(String.class), "%" + model.getVersion() + "%"));
}
// 日期
if (model.getUpload_time() != null) {
Date startDate = model.getUpload_time();
Date endDate = new Date();
// 处理字符串时间
// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
// try {
// startDate = format.parse(date);
// } catch (ParseException e) {
// startDate = new Date(946656000000L);//2000 01 01
// }
// endDate = startDate;
// Calendar calendar = Calendar.getInstance() ;
// calendar.setTime(endDate);
// calendar.add(Calendar.DATE, 1);
// endDate = calendar.getTime();
// calendar = null;
list.add(cb.between(root.get("upload_time"), startDate, endDate));
}
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
}
});
return result;
}
}
更多详情可参考
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/