写点什么

Spring 全家桶之 Spring Data JPA(三)

作者:小白
  • 2022 年 8 月 21 日
    上海
  • 本文字数:2373 字

    阅读完需:约 8 分钟

Spring 全家桶之 Spring Data JPA(三)

如何在 Spring Data JPA 中实现动态查询

Specifications 动态查询方法

T findOne(Specification<T> spec); //查询单个List<T> findAll(Specification<T> spec); //查询列表List<T> findAll(Specification<T> spec, Sort sort); //排序查询Page<T> findAll(Specification<T> spec, Pageable pageable); //分页查询long count(Specification<T> spec); //统计查询
复制代码

查询条件-Specification

自定义 Specification 实现类,实现


Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
复制代码


构造查询条件,参数如下


  • Root:查询的对象,查询条件/属性都可以从 root 对象中获取

  • CriteriaQuery:上层查询对象,定义查询方式,一般不用

  • CriteriaQueryBuilder:查询对象的构造器,封装了较多的查询条件

动态查询实现

1.新建 Maven 项目,加入 Maven 依赖 2.新建 entity 包,增加实体类 Customer3.新建 dao 包,增加 CustomerDao4.在 test 包中新建 dao 包,增加 CustomerDao

findOne(Specification<T> spec)

直接在 CustomerDaoTest 中书写测试方法


@Testpublic void testFindOne(){    // 匿名内部类    Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {        // 构造查询条件,实现toPredicate方法        //1.获取比较的属性        Path<Object> custName = root.get("custName");        //2.构造查询条件,equal为精准匹配        Predicate thor_odin = cb.equal(custName, "Thor Odin");        return thor_odin;    };
Customer one = customerDao.findOne(specification); System.out.println(one);}
复制代码


使用了 lambda 表达式实现 Specification 匿名内部类,测试结果如下



多个条件查询,使用 and 或者 or 连接多个查询条件


@Testpublic void testFindOneByMultiCondition(){    Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {        // 构造查询条件,实现toPredicate方法        //1.获取比较的属性        Path<Object> custName = root.get("custName");        Path<Object> custIndustry = root.get("custIndustry");        //2.构造查询条件,equal为精准匹配        Predicate thor_odin = cb.equal(custName,"Thor Odin");        Predicate asgard = cb.equal(custIndustry, "God of Thunder");        // 组合查询条件,以与的形式组合查询条件,也可以使用or        Predicate mutil = cb.and(thor_odin, asgard);        return mutil;    };
Customer one = customerDao.findOne(specification); System.out.println(one);}
复制代码


findAll(Specification<T> spec)实现模糊查询

/** * equal方法可以直接使用path属性及属性值的方式得到Predicate对象 * gt,lt,ge,le,like需要使用path属性.as(属性类型.class)及属性vlaue来得到Predicate对象 */@Testpublic void testFindAllByLike(){    Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {        // 构造查询条件,实现toPredicate方法        //1.获取比较的属性        Path<Object> custSource = root.get("custSource");
Predicate like = cb.like(custSource.as(String.class), "FB%"); return like; };
List<Customer> all = customerDao.findAll(specification); for (Customer customer : all) { System.out.println(customer); }}
复制代码


List<T> findAll(Specification<T> spec, Sort sort); 排序查询

    @Test    public void testFindAllByLikeAsc(){        Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {            // 构造查询条件,实现toPredicate方法            //1.获取比较的属性            Path<Object> custSource = root.get("custSource");
Predicate like = cb.like(custSource.as(String.class), "FB%"); return like; };
// 排序规则,倒叙排列 Sort sort = new Sort(Sort.Direction.DESC,"custId");

List<Customer> all = customerDao.findAll(specification,sort); for (Customer customer : all) { System.out.println(customer); } }}
复制代码


使用 Sort 构造排序规则,需要两个参数,排序规则和排序字段,输出结果如下


Page<T> findAll(Specification<T> spec, Pageable pageable)分页查询

先通过 save()方法往表中添加数据


@Testpublic void testInsert(){    for (int i = 1; i <= 30; i++) {        Customer customer = new Customer();        customer.setCustName("Spider Army No " + i);        customer.setCustIndustry("Queen");        customer.setCustLevel("LV 1");        customerDao.save(customer);    }}
复制代码


新增分页测试代码


@Testpublic void testPaging(){    Specification spec = null;    // 当前查询页数和每页查询数量    Pageable pageable = new PageRequest(0,5);    Page<Customer> all = customerDao.findAll(null,pageable);    //获取总页数    System.out.println(all.getTotalPages());    // 获取数据总量    System.out.println(all.getTotalElements());    // 获取当前页数据集合    List<Customer> content = all.getContent();    // 遍历集合,得到当前页的所有Customer数据    for (Customer customer : content) {        System.out.println(customer);    }}
复制代码


执行分页查询测试



成功查出首页数据

用户头像

小白

关注

QA 2019.08.05 加入

微信号JingnanSJ或者公众号RiemannHypo获取异步和图灵系列书籍

评论

发布
暂无评论
Spring 全家桶之 Spring Data JPA(三)_8月月更_小白_InfoQ写作社区