Spring Boot使用JPA多条件查询mysql

我们在上一章节已经学习了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;
    }

}

新建实体相关的接口继承JpaSpecificationExecutor

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/

你可能感兴趣的:(SpringBoot)