Spring Data JPA系列:数据查询(Specification)(一)

在JPA中,如果用@Query查询有诸多不便,因此JPA提供了基于Criteria API的查询,比@Query查询更灵活方便,这篇文章就简单说说Specification的简单使用。
这篇文章是参考:Useing JPA Criteria API ,相关代码如下所示:

1、定义一个继承JpaSpecificationExecutor的接口:

import com.example.demo.dto.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/**
 * Created by Administrator on 2017/7/12 0012.
 */
public interface CustomerSpecificationRepository extends JpaRepository<Customer,Long>,
    JpaSpecificationExecutor<Customer> {
}

这里只是继承接口声明的方法,比如

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);

包含了常用的查询单个对象,查询数据集合,查询分页数据集合,查询带排序参数的数据集合,查询数据的大小,这些都是常用的数据结果集,因此可以不用做其他定义即可直接使用。

2、创建SpecificationFactory工具类

import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.Path;
/**
 * Created by Administrator on 2017/7/13 0013.
 */
public final class SpecificationFactory {
    public static Specification containsLike(String attribute, String value) {
        return (root, query, cb) -> cb.like(root.get(attribute), "%" + value + "%");
    }
    public static Specification isBetween(String attribute, int min, int max) {
        return (root, query, cb) -> cb.between(root.get(attribute), min, max);
    }
    public static Specification isBetween(String attribute, double min, double max) {
        return (root, query, cb) -> cb.between(root.get(attribute), min, max);
    }
    public static <T extends Enum<T>> Specification enumMatcher(String attribute, T queriedValue) {
        return (root, query, cb) -> {
            Path<T> actualValue = root.get(attribute);
            if (queriedValue == null) {
                return null;
            }
            return cb.equal(actualValue, queriedValue);
        };
    }
}

这个工具类定义了一些基本的查询,包括模糊匹配(containsLike),数值区间(isBetween)以及枚举类参数匹配(enumMatcher),这些也是在查询中常用的方法,在查询的时候,通过Specifications进行调用组织参数,即可获得接口Specification的实例,然后用于查询。

3、在CustomerController中添加测试方法

  • 初始化
    @Autowired
    private CustomerSpecificationRepository csr;
  • 单一条件查询
    @RequestMapping("/spec")
    public void specificationQuery(){
        Specification<Customer> spec = SpecificationFactory.containsLike("lastName","bau");
        Pageable pageable = new PageRequest(0,5, Sort.Direction.DESC,"id");
        Page<Customer> page = csr.findAll(spec,pageable);
        System.out.println(page);
        System.out.println(page.getTotalElements());
        System.out.println(page.getTotalPages());
        for (Customer c:page.getContent()){
            System.out.println(c.toString());
        }
    }
  • 复合条件查询
    @RequestMapping("/spec2")
    public void specificationQuery2(){
        Specification<Customer> spec2 = Specifications
                .where(SpecificationFactory.containsLike("firstName","bau"))
                .or(SpecificationFactory.containsLike("lastName","bau"));
        Pageable pageable = new PageRequest(0,5, Sort.Direction.DESC,"id");
        Page<Customer> page = csr.findAll(spec2,pageable);
        System.out.println(page);
        System.out.println(page.getTotalElements());
        System.out.println(page.getTotalPages());
        for (Customer c:page.getContent()){
            System.out.println(c.toString());
        }
    }

至此,使用Specification通过Criteria API进行查询,获得查询的结果集。相较于@Query方式的查询定义,更人性化和方便操作,后面在对Criteria API的使用进一步深入,会继续给出相关实践,敬请期待。

参考:
官方文档
PDF官方文档下载
API官方文档
JPQL文档

DEMO示例:https://github.com/icnws/spring-data-jpa-demo

7 thoughts on “Spring Data JPA系列:数据查询(Specification)(一)

  1. 楼主好,我想请问下,你这自定义查询所针对的分页查询都是假分页,大数据的时候不是超级缓慢,你如何避免的呢?

    1. 现在还在摸索,考虑到大量数据查询缓慢的问题,需要根据hibernate相关的优化来进行调整

    2. 通过PageRequest方法创建的分页查询并不是假分页,是真分页,比如mysql是limit ?,?,只是当查询第一页的时候,直接limit ?而已

    1. 这方面还没有用到,最近会将数据查询(二)等给出,join相关的用法写法

  2. 请教下这里的return (root, query, cb) -> cb.like,中的root、query、cb是个什么用法?
    这些变量是从哪里来的?

    1. 这是Specification这个接口提供的,他们属于JPA Criteria API,我最近也在看相关文档

Leave a Comment

电子邮件地址不会被公开。 必填项已用*标注