【Spring Data JPA自学笔记四】动态查询

2023-11-08

上一期介绍了Spring Data JPA的各种查询方法,这一期来详细讲一下动态查询类,JpaSpecificationExecutor.

JpaSpecificationExecutor接口

JpaSpecificationExecutor提供了findOnefindAllcount方法的几个重载:

  • Optional<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); 根据规范统计个数

上一期我们提到了PagingAndSortingRepository接口,这个接口提供了排序和分页查找的方法,然而它却不支持条件查询,JpaSpecificationExecutor接口解决了这个问题。

初见Specification类

Specification类用于确定规范,那么这个规范要如何确定呢?接下来我们细看一下这个类:

Specification需要提供一个泛型确定实体类,类中有一个toPredicate方法需要我们重载,而toPerdicate方法拥有3个参数:

  • root 用于获取类属性
  • criteriaQuery 添加条件(不常用)
  • criteriaBuilder 添加条件

举例:

  @Test
  @Transactional
  public void TestFind() {
    Specification<User> spec = new Specification<User>() {
      @Override
      public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        Path<Object> name = root.get("name");
        return criteriaBuilder.equal(name, "冬马和纱");
      }
    };
    
    List<User> userList = userDao.findAll(spec);
    for (User user : userList) {
      System.out.println(user);
    }
  }

这里笔者使用root的get方法获取一个类属性,注意返回值使用Path<Object>接收;接着使用criteriaBuilder添加equal条件:

  • criteriaBuilder.equal(name, "冬马和纱")name = "冬马和纱"

返回结果:

Hibernate: select user0_.u_id as u_id1_1_, user0_.u_address_id as u_addres3_1_, user0_.u_name as u_name2_1_ from user user0_ where user0_.u_name=?
Hibernate: select address0_.a_id as a_id1_0_0_, address0_.a_name as a_name2_0_0_ from address address0_ where address0_.a_id=?
ID: 1, Name: 冬马和纱, Address: 北京

Process finished with exit code 0

当然,在Java 8及以上版本,我们可以使用Lambda表达式使代码更美观:

    Specification<User> spec = (Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
      Path<Object> name = root.get("name");
      return criteriaBuilder.equal(name, "冬马和纱");
    };

Specification的更多功能

Specification的条件

对于toPredicate方法中的criteriaBuilder参数,除了equal判等之外,还有更多强大的功能:

  • equal / notEqual 判等
  • like / notLike 模糊查询
  • gt / ge / lt / le 大于、大于等于、小于、小于等于
  • between 范围查询

需要注意的是,除了判等方法可以直接传递参数之外,其他方法都需要使用as指定数据类型,如:

  @Test
  @Transactional
  public void TestFind() {
    Specification<User> spec = (Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
      Path<Object> name = root.get("name");
      return criteriaBuilder.like(name.as(String.class), "冬马%");
    };

    List<User> userList = userDao.findAll(spec);
    for (User user : userList) {
      System.out.println(user);
    }
  }

返回结果:

Hibernate: select user0_.u_id as u_id1_1_, user0_.u_address_id as u_addres3_1_, user0_.u_name as u_name2_1_ from user user0_ where user0_.u_name like ?
Hibernate: select address0_.a_id as a_id1_0_0_, address0_.a_name as a_name2_0_0_ from address address0_ where address0_.a_id=?
ID: 1, Name: 冬马和纱, Address: 北京

Process finished with exit code 0

Specification多条件查询

toPredicatecriteriaBuilder参数提供了条件处理的方法:and / or / not.

很好理解,不多做解释。

举例:

  @Test
  @Transactional
  public void TestFind() {
    Specification<User> spec = (Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
      Path<Object> id = root.get("id");
      Path<Object> address = root.get("address");
      Predicate p1 = criteriaBuilder.ge(id.as(Integer.class), 2);
      Predicate p2 = criteriaBuilder.equal(address, 10001);
      return criteriaBuilder.and(p1, p2);
    };

    List<User> userList = userDao.findAll(spec);
    for (User user : userList) {
      System.out.println(user);
    }
  }

返回结果:

Hibernate: select user0_.u_id as u_id1_1_, user0_.u_address_id as u_addres3_1_, user0_.u_name as u_name2_1_ from user user0_ where cast(user0_.u_id as signed)>=2 and user0_.u_address_id=10001
Hibernate: select address0_.a_id as a_id1_0_0_, address0_.a_name as a_name2_0_0_ from address address0_ where address0_.a_id=?
ID: 3, Name: 鹿目圆香, Address: 北京
ID: 5, Name: 雪之下雪乃, Address: 北京

Process finished with exit code 0

排序和分页

在旧版本中,SortPageable可以通过构造方法设定参数,然而在2.2版本之后,构造方法不再被支持。

使用Sort

新版本中使用Sort.by设定参数,第一个参数表示排序方向,第二个参数表示排序对象。

举例:

  @Test
  @Transactional
  public void TestFind() {
    Specification<User> spec = (Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
      Path<Object> address = root.get("address");
      return criteriaBuilder.equal(address, 10001);
    };

    List<User> userList = userDao.findAll(spec, Sort.by(Sort.Direction.DESC, "id"));
    for (User user : userList) {
      System.out.println(user);
    }
  }

返回结果:

Hibernate: select user0_.u_id as u_id1_1_, user0_.u_address_id as u_addres3_1_, user0_.u_name as u_name2_1_ from user user0_ where user0_.u_address_id=10001 order by user0_.u_id desc
Hibernate: select address0_.a_id as a_id1_0_0_, address0_.a_name as a_name2_0_0_ from address address0_ where address0_.a_id=?
ID: 5, Name: 雪之下雪乃, Address: 北京
ID: 3, Name: 鹿目圆香, Address: 北京
ID: 1, Name: 冬马和纱, Address: 北京

Process finished with exit code 0

如果要进行多条件排序查询,可以使用Sort.and(Sort),本文不再演示。

使用PageRequest

PageRequest.of()方法返回一个Pageable对象,需要提供两个参数,第一个参数表示开始页(从第零页开始),第二个参数表示每页的数据量。

findAll(Spec, Pageable)方法返回一个Page对象,这个对象有以下常用方法:

  • getTotalElements 返回元素总数
  • getTotalPages 返回总页数
  • getContent 以List形式返回当前页面的元素

举例:

  @Test
  @Transactional
  public void TestFind() {
    Specification<User> spec = (Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
      Path<Object> id = root.get("id");
      return criteriaBuilder.gt(id.as(Integer.class), 1);
    };
    Page<User> userPage = userDao.findAll(spec, PageRequest.of(1, 2));
    List<User> userList = userPage.getContent();
    for (User user : userList) {
      System.out.println(user);
    }
  }

返回结果:

Hibernate: select user0_.u_id as u_id1_1_, user0_.u_address_id as u_addres3_1_, user0_.u_name as u_name2_1_ from user user0_ where cast(user0_.u_id as signed)>1 limit ?, ?
Hibernate: select address0_.a_id as a_id1_0_0_, address0_.a_name as a_name2_0_0_ from address address0_ where address0_.a_id=?
Hibernate: select address0_.a_id as a_id1_0_0_, address0_.a_name as a_name2_0_0_ from address address0_ where address0_.a_id=?
Hibernate: select count(user0_.u_id) as col_0_0_ from user user0_ where cast(user0_.u_id as signed)>1
ID: 5, Name: 雪之下雪乃, Address: 北京
ID: 10, Name: 由比滨结衣, Address: 深圳

Process finished with exit code 0
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Spring Data JPA自学笔记四】动态查询 的相关文章

随机推荐

  • 定时任务动态管理-Scheduled

    文章目录 前言 一 架构流程图 二 代码实现流程 1 引入库 2 代码流程 前言 定时任务动态管理分为两种方式 方式一 Web前台配置Trigger触发器 关联Cron ThreadPoolTaskScheduler类创建Scheduler
  • 蓝桥杯每日一题2023.9.21

    蓝桥杯2021年第十二届省赛真题 异或数列 C语言网 dotcpp com 题目描述 Alice 和 Bob 正在玩一个异或数列的游戏 初始时 Alice 和 Bob 分别有一个整数 a 和 b 有一个给定的长度为 n 的公共数列 X1 X
  • 与ajax类似的技术,介绍Ajax与jQuery技术

    Ajxs技术 异步的JavaScript与XML 已有多种技术的组合 Ajax的优点是什么 1 可以实现客户端的异步请求操作2 进而在不需要刷新页面的情况下与服务器进行通信 减少用户的等待时间3 减轻服务器和带宽的负担 提供更好的服务响应
  • linux socket bind 内核详解,Socket与系统调用深度分析(示例代码)

    1 什么是系统调用 操作系统通过系统调用为运行于其上的进程提供服务 当用户态进程发起一个系统调用 CPU 将切换到 内核态 并开始执行一个 内核函数 内核函数负责响应应用程序的要求 例如操作文件 进行网络通讯或者申请内存资源等 在Linux
  • 在 CentOS 上安装 Docker 引擎

    在 CentOS 上安装 Docker 引擎 预计阅读时间 11分钟 要在 CentOS 上开始使用 Docker 引擎 请确保 满足先决条件 然后 安装 Docker 先决条件 操作系统要求 要安装 Docker Engine 您需要 C
  • 双向广搜(bfs)

    双向广度优先搜索 广度优先搜索遵循从初始结点开始一层层扩展直到找到目标结点的搜索规则 它只能较好地解决状态不是太多的情况 承受力很有限 如果扩展结点较多 而目标结点又处在较深层 采用前文叙述的广度搜索解题 搜索量巨大是可想而知的 往往就会出
  • GDI+ Graphics绘文字定位不准,显示偏差问题

    拿来主义人员速达 取一般的版式 TGPStringFormat 对象 使用可以达到精准定位显示效果 format GenericTypographic MFC开发中需要自绘控件 使用Graphics绘文字时出现位置偏右偏下问题 显示效果如下
  • JSR-303使用依赖jar包

    jboss logging 3 1 0 GA jar slf4j api 1 5 8 jar hibernate validator 4 3 0 Final jar validation api 1 1 0 Alpha1 jar java
  • springboot 定时任务(线程配置,并行【同步】、异步等)

    定时任务 实现方式 SpringBoot自带的Scheduled 可以将它看成一个轻量级的Quartz 而且使用起来比Quartz简单许多 本文主要介绍 执行方式 单线程 串行 多线程 并行 创建定时任务 Component EnableS
  • 数据库主从同步的作用是什么,如何解决数据不一致问题?

    Redis是一种高性能的内存数据库 而MySQL是基于磁盘文件的关系型数据库 相比于Redis来说 读取速度会慢一些 但是功能强大 可以用于存储持久化的数据 在实际工作中 我们常常将Redis作为缓存与MySQL配合来使用 当有数据访问请求
  • Android 使用Lottie的三个小技巧

    Android 使用Lottie的三个小技巧 Shawn 文章目录 Android 使用Lottie的三个小技巧 I 开启硬件加速 II 通过添加AnimatorListener来控制动画行为 III 通过设置播放速度来实现动画倒放 I 开
  • 构建天气数据API:使用Scrapyd提供实时天气信息接口

    目录 1 天气数据API的重要性 2 选择合适的气象数据源 3 构建天气数据爬虫 4 使用Scrapyd进行
  • 4.3.1 位置变化动作

    4 3 1 位置变化动作 2013 05 21 10 12 火烈鸟网络科技 人民邮电出版社 我要评论 0 字号 T T Cocos2d x高级开发教程 第4章动作 在这一章中 我们将为大家详细介绍各种动作的使用方法 读完本章后 读者将会学到
  • App Transport Security has blocked a cleartext HTTP

    问题 App Transport Security has blocked a cleartext HTTP http resource load since it is insecure Temporary exceptions can
  • linux查找含有指定字符串的文件

    1 使用find进行查找 find oracle apache tomcat 8 5 59 xml xargs grep 1521 2 使用grep查找 grep rn 搜索的内容 路径
  • linux终端Bash换成zsh后,环境变量失效的解决方案

    安装了oh my zsh后 发现node ng什么的命令都失效了 第一反映是环境变量失效 忘记了怎么配置 Search on the Internet half an hour 说多了都是泪 一直找不到解决方法 最终问了项目老大 一句话点明
  • 五.安装gitlab

    1 下载安装 gitlab ce 15 9 1 ce 0 el7 x86 64 rpm 下载安装包 wget https mirrors tuna tsinghua edu cn gitlab ce yum el7 gitlab ce 15
  • python连接oracle数据库查询

    直接上源码说明吧 如下 开头引入必须的插件 连接oracle需要导入cx Oracle coding utf8 import cx Oracle import sys os from selenium import webdriver 编码
  • C++中string如何实现字符串分割函数split()——4种方法

    如 string str1 This is a test string str2 This is a test string str2 This is a test 我们如何将以上字符串按照某种分隔符 将其分割成四个子串 其值分别为 Thi
  • 【Spring Data JPA自学笔记四】动态查询

    文章目录 JpaSpecificationExecutor接口 初见Specification类 Specification的更多功能 Specification的条件 Specification多条件查询 排序和分页 使用Sort 使用P