71、Spring Data JPA 的 样本查询--参数作为样本去查询数据库的数据,也可以定义查询的匹配规则

news2024/11/25 10:57:38

★ 样本查询

给Spring Data传入一个样本数据,Spring Data就能从数据库中查询出和样本相同的数据。

被查询的数据并不需要和样本是完全相同的,可能只需要和样本有几个属性是相同的。

总结:
样本查询–就是把参数作为样本去查询数据库的数据,根据自定义的匹配规则,如果对应上就能把数据查出来
样本查询也可以定义其中查询的一些匹配规则

▲ 样本查询的API(QueryByExampleExecutor):

JpaRepository继承了QueryByExampleExecutor接口,该接口提供了如下“样本查询”方法:

- <S extends T> Optional<S> findOne(Example<S> example);
- <S extends T> Iterable<S> findAll(Example<S> example);
- <S extends T> Iterable<S> findAll(Example<S> example, Sort sort);
- <S extends T>   Page<S>   findAll(Example<S> example, Pageable pageable);
- <S extends T>   long      count(Example<S> example);
- <S extends T>   boolean   exists(Example<S> example);

只要让DAO接口继承该QueryByExampleExecutor接口,DAO组件就可调用上面的样本查询方法。
——方法实现不要你操心,Spring Data会负责搞定它们。

▲ 创建Example

Example查询的关键在于Example参数,它提供了如下两个of()类方法来创建Example对象:

 - of(T probe):以probe对象创建最简单的Example对象,使用默认的匹配规则。
                要求被查询对象与样本对象所有属性都严格相等。

 - of(T probe, ExampleMatcher matcher):以probe创建Example对象,并使用matcher指定匹配规则。

▲ ExampleMatcher提供了如下静态方法来创建实例:

- static ExampleMatcher matching():创建一个需要所有属性都匹配的匹配器。 (and运算符)
- static ExampleMatcher matchingAll():完全等同于matching()方法
- static ExampleMatcher matchingAny():创建一个只要任意一个属性匹配的匹配器。(or运算符)

▲ ExampleMatcher还可通过如下方法来指定对特定属性的匹配规则:

- withIgnoreCase():指定属性匹配时默认不区分大小写。

- withIgnoreCase(String... propertyPaths):指定propertyPaths参数列出的属性在匹配时不区分大小写。

- withIgnoreNullValues():指定不比较Example对象中属性值为null的属性。

- withIgnorePaths(String... ignoredPaths):指定忽略ignoredPaths参数列出的属性,也就是这些属性不参与匹配。

- withIncludeNullValues():强行指定要比较Example对象中属性值为null的属性。

- withMatcher(String propertyPath, 比较器):对propertyPath参数指定的属性使用专门的匹配规则。

▲ 样本查询的步骤:

(1) 让DAO接口要么继承JpaRepository(是QueryByExampleExecutor的子接口),
      或者增加继承QueryByExampleExecutor

(2) DAO组件可调用QueryByExampleExecutor的样本查询方法

代码演示:

需求:根据一个对象中的某些属性作为样本,去数据库查询数据

要实现样本查询,
Dao接口需要继承 JpaRepository 接口,
或者增加继承 QueryByExampleExecutor 接口

接口可以继承接口,并且可以继承不只一个接口,但是不能实现接口。
因为接口的成员方法都具有抽象属性,不具有方法体,无法实现继承的接口

1、这样实现样本查询的接口继承
在这里插入图片描述
2、不需要在StudentDao组件写方法,或者写sql语句,直接在测试类进行查询方法的调用,因为DAO组件会调用QueryByExampleExecutor的样本查询方法,不用我们写。

DAO组件调用QueryByExampleExecutor的样本查询方法时,
查询的默认的匹配规则,要求被查询对象与样本对象所有属性都严格相等。

如图:
样本查询的条件都符合,但是没查出数据,是因为没有添加匹配规则,
而默认的匹配规则,要求被查询对象与样本对象所有属性都严格相等。
而上面只有student的两个属性,其他没写上去就会为null,
所以就查询对象与样本对象的所有属性没有全部相等。
所以查不出数据
没有指定匹配规则,所以要求样本对象(s) 和 查询对象(Student) 的所有属性都相等才行

测试1:没有添加匹配规则的测试
默认匹配规则:要求被查询对象与样本对象所有属性都严格相等
在这里插入图片描述

测试2:添加匹配规则的测试
添加匹配规则:不比较 Null 值
在这里插入图片描述

解释:.withIgnorePaths (“id”, “gender”)
id 是 Integer 类型,默认值是null , 所以也可以不排除
基本类型的属性,如果不作为参数去查询,就需要排除出去
在这里插入图片描述

测试3:添加匹配规则的测试
添加匹配规则:调用 matchingAny() ,相当于 OR 运算符,只要有一个参数和查询的student对象对应得上,就能将该对象查出来
在这里插入图片描述

测试4:添加匹配规则的测试
添加的匹配规则:.withMatcher()
作用:
指定自己的匹配规则,指定要求以样本属性值作为结尾即可。
相当于查询 address like "%洞"就可以了,而不是 address = “洞”

需求:查询地址匹配指定后缀的student

在这里插入图片描述

匹配规则方法: .withMatcher() ,还能这样写,更灵活
.withMatcher(“address”,matcher -> matcher.endsWith())
也是以该样本属性作为后缀进行查询
在这里插入图片描述

完整代码

StudentDao

这个接口只需要再继承 QueryByExampleExecutor 这个接口就可以了,
或者直接继承 JpaRepository 接口也可以
在这里插入图片描述
不需要在StudentDao组件写方法,或者写sql语句,直接在测试类进行查询方法的调用,因为DAO组件会调用QueryByExampleExecutor的样本查询方法,不用我们写。

package cn.ljh.app.dao;

import cn.ljh.app.domain.Student;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

import java.util.List;

//CrudRepository 的第一个泛型参数是被操作的实体类型,第二个参数是实体的主键类型
//public interface StudentDao extends CrudRepository<Student,Integer>

//如果要做样本查询,Dao接口需要继承 JpaRepository 接口,
//public interface StudentDao extends JpaRepository<Student,Integer>

//或者增加继承 QueryByExampleExecutor 接口
public interface StudentDao extends CrudRepository<Student,Integer> , QueryByExampleExecutor<Student>
{
    //查询年龄大于指定参数的学生
    List<Student> findByAgeGreaterThan(int startAge);

    //根据年龄和班级名称查询学生
    //Age 和 ClazzName 用 And 连接起来,表示两个查询条件,
    //ClazzName这两个单词中间没有And连接起来,表示是一个路径写法,表示是Clazz类的name属性
    List<Student> findByAgeAndClazzName(int age , String clazzName);

    //根据地址后缀进行分页查询,查询 address 带有 "洞" 的学生并进行分页
    Page<Student> findByAddressEndingWith(String addrSuffix, Pageable pageable);
}

StudentDaoTest

package cn.ljh.app.dao;


import cn.ljh.app.domain.Student;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.*;

import java.util.List;

//SpringBootTest.WebEnvironment.NONE : 表示不需要web环境
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class StudentDaoTest
{
    @Autowired
    private StudentDao studentDao;

    /**
     * @ValueSource: 每次只能传一个参数
     * @CsvSource:每次可以传多个参数
     */

    //需求:查询年龄大于指定参数的记录
    //参数化测试
    @ParameterizedTest
    @ValueSource(ints = {20, 200})
    public void testFindByAgeGreaterThan(int startAge)
    {
        List<Student> students = studentDao.findByAgeGreaterThan(startAge);
        students.forEach(System.err::println);
    }

    //根据年龄和班级名称查询学生
    //Age 和 ClazzName 用 And 连接起来,表示两个查询条件,
    //ClazzName这两个单词中间没有And连接起来,表示是一个路径写法,表示是Clazz类的name属性
    @ParameterizedTest
    //参数一个是int,一个是String,这个注解在传参的时候会自动进行类型转换
    @CsvSource(value = {"20,超级A营", "18,超级D班"})
    public void testFindByAgeAndClazzName(int age, String clazzName)
    {
        List<Student> students = studentDao.findByAgeAndClazzName(age, clazzName);
        students.forEach(System.err::println);
    }


    //pageNo: 要查询哪一页的页数 , pageSize: 每页显示的条数
    @ParameterizedTest
    @CsvSource({"洞,2,3", "洞,1,4", "洞,3,2"})
    public void testFindByAddressEndingWith(String addrSuffix, int pageNo, int pageSize)
    {
        //分页对象,此处的pageNo是从0开始的,0代表第一页,所以这里的 pageNo 要 -1
        Pageable pageable1 = PageRequest.of(pageNo - 1, pageSize);
        Page<Student> students = studentDao.findByAddressEndingWith(addrSuffix, pageable1);

        int number = students.getNumber() + 1;
        System.err.println("总页数:" + students.getTotalPages());
        System.err.println("总条数:" + students.getTotalElements());
        System.err.println("当前第:" + number + " 页");
        System.err.println("当前页有:" + students.getNumberOfElements() + " 条数据");
        students.forEach(System.err::println);
    }

    //==============测试样本查询从这里开始=====================================================
    
    //根据一个对象中的某些属性作为样本,去数据库查询数据
    @ParameterizedTest
    @CsvSource({"孙悟空,500", "猪八戒,200"})
    public void exampleTest1(String name, int age)
    {
        Student s = new Student();
        s.setName(name);
        s.setAge(age);
        //没有指定匹配规则,所以要求样本对象(s) 和 查询对象(Student) 的所有属性都相等才行
        Iterable<Student> students = studentDao.findAll(Example.of(s));
        students.forEach(System.err::println);
    }

    //根据一个对象中的某些属性作为样本,去数据库查询数据
    @ParameterizedTest
    @CsvSource({"孙悟空,500", "猪八戒,200"})
    public void exampleTest2(String name, int age)
    {
        Student s = new Student();
        s.setName(name);
        s.setAge(age);
        Iterable<Student> students = studentDao.findAll(Example.of(s,
                //添加匹配规则
                ExampleMatcher.matching()
                        //不比较Null值
                        .withIgnoreNullValues()
                        //不比较id、gender,因为gender是基本类型,有默认值,所以需要排除在外
                        .withIgnorePaths("gender")
        ));
        students.forEach(System.err::println);
    }


    //根据一个对象中的某些属性作为样本,去数据库查询数据
    @ParameterizedTest
    @CsvSource({"孙悟空,99999", "猪八戒,200"})
    public void exampleTest3(String name, int age)
    {
        Student s = new Student();
        s.setName(name);
        s.setAge(age);
        Iterable<Student> students = studentDao.findAll(Example.of(s,
                //添加匹配规则:Or 运算符,只要有一个属性对得上就查出来
                ExampleMatcher.matchingAny()
                        //不比较Null值
                        .withIgnoreNullValues()
                        //不比较id、gender
                        .withIgnorePaths("id", "gender")
        ));
        students.forEach(System.err::println);
    }

    //查询地址匹配指定后缀的student
    @ParameterizedTest
    @ValueSource(strings = {"洞", "河"})
    public void exampleTest4(String addressSuffix)
    {
        Student s = new Student();
        s.setAddress(addressSuffix);
        Iterable<Student> students = studentDao.findAll(Example.of(s,
                //添加匹配规则:Or 运算符,只要有一个属性对得上就查出来
                ExampleMatcher.matchingAny()
                        //不比较Null值
                        .withIgnoreNullValues()
                        //如果参数查询没用到 gender , age 这些基本类型,则排除在外不进行比较,因为有默认值
                        .withIgnorePaths("gender", "age")
                        //指定自己的匹配规则,指定要求以样本属性值作为结尾即可。
                        //相当于查询 address like "%洞"就可以了,而不是 address = "洞"
                        .withMatcher("address",
                                ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.ENDING))
        ));
        students.forEach(System.err::println);
    }

    //查询地址匹配指定后缀的student
    @ParameterizedTest
    @ValueSource(strings = {"洞", "河"})
    public void exampleTest5(String addressSuffix)
    {
        Student s = new Student();
        s.setAddress(addressSuffix);
        Iterable<Student> students = studentDao.findAll(Example.of(s,
                //添加匹配规则:Or 运算符,只要有一个属性对得上就查出来
                ExampleMatcher.matchingAny()
                        //不比较Null值
                        .withIgnoreNullValues()
                        //如果参数查询没用到 gender , age 这些基本类型,则排除在外不进行比较,因为有默认值
                        .withIgnorePaths("gender", "age")
                        //指定自己的匹配规则,指定要求以样本属性值作为结尾即可。
                        //相当于查询 address like "%洞"就可以了,而不是 address = "洞"
                        //更灵活的写法matcher -> matcher.endsWith()
                        .withMatcher("address",matcher -> matcher.endsWith())
        ));
        students.forEach(System.err::println);
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1015136.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一、 计算机网络概论

一、计算机网络概论 1、计算机网络概述 1.1、概念 计算机网络是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统 是一些互连的、自治的计算机系统的集合 以能够相互共享资源的方…

【Git】Git 变基(rebase)以及rebase和merge之间的区别

Git 变基 1.变基 — rebase 在 Git 中整合来自不同分支的修改主要有两种方法&#xff1a;merge 以及 rebase。 在前面的文章中已经介绍了merge&#xff0c;这里我们来学习另一个指令rebase。 变基的基本操作 回顾之前在 分支的合并 中的一个例子&#xff0c;在该例子中&am…

go Gorm连接数据库,并实现增删改查操作

Gorm 1. 准备工作 首先进入终端下载我们需要的包&#xff08;确保go和mysql安装完成&#xff0c;并设置了环境变量&#xff09; go get -u gorm.io/driver/mysql go get -u gorm.io/gorm有两份官方文档有对 GORM 更详细的讲解。 创建 | GORM - The fantastic ORM library f…

EndNote21 | 账户同步问题

问题&#xff1a;无法同步&#xff0c;提示如下图所示。 原因&#xff1a;网络问题。 解决方法&#xff1a;国内网络无法实现同步&#xff0c;解决上网问题即可。

【数据结构】结构实现:顺序存储模式实现堆的相关操作

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;数据结构 &#x1f525;该文章着重讲解了使用顺序结构实现堆的插入和删除等操作。 目录&#xff1a; &#x1f30d;二叉树的顺序结构&#x…

什么触控笔好用又便宜?ipad2022手写笔推荐

随着无纸化的广泛使用&#xff0c;和Apple pencil的出现&#xff0c;电容笔逐渐成为生产力的主要部分&#xff0c;像中性笔一样的电容笔&#xff0c;它不止具有小巧的身材&#xff0c;续航和功能都很在线&#xff0c;无论是在学习上还是工作上&#xff0c;电容笔逐渐成为人们缺…

Jenkis 配置钉钉通知

1、安装插件Ding Talk 2、钉钉上的配置 打开钉钉创建机器人&#xff0c;勾选加签&#xff0c;后面jenkins要用到 2.1 webhook -jenins界面要配置的地址&#xff1a;https://。。。。。。 2.2 jenkins 界面的加密地址 3、jenkins界面上的配置 在系统管理中找到安装好的插件&a…

部署docker image到AWS

1. 在AWS里创建ECR 仓库 2. 进入自己的Repository. 然后点击View push commands 3. 记一下这些命令 4. 登陆AWS cloud9 , 利用git clone 你的代码 5. 依次执行步骤3里的所有命令。最后你发现你的ECR里有了一个docker镜像 aws ecr-public get-login-password --region us-eas…

(CVPR-2023)InternImage:利用可变形卷积探索大规模视觉基础模型

InternImage&#xff1a;利用可变形卷积探索大规模视觉基础模型 Title&#xff1a;InternImage: Exploring Large-Scale Vision Foundation Models with Deformable Convolutions paper是上海AI Lab发表在CVPR 2023的工作 paper链接 Abstract 与近年来大规模视觉变换器&#x…

【Vue】入门及生命周期(前后端分离)

目录 一、Vue简介 1、Vue.js是什么 2、库和框架的区别 2.1 库(Library) 2.2 框架(Framework) 3、MVVM的介绍 二、Vue入门 1、Vue快速入门 2、Vue的优势 三、Vue事件 四、Vue生命周期 1、实例 一、Vue简介 1、Vue.js是什么 Vue是一款流行的构建用户界面(UI)的[渐进式…

vue3-admin-element安装

1、直接点此链接进入下载 https://gitee.com/hu-snail/vue3-admin-element-template 2、下载完毕之后是个压缩包&#xff0c;解压 然后直接可以运行到vscode或HBuilder中 3、下载依赖&#xff1a;我使用的npm下载 npm i npm i serve启动 运行&#xff1a;npm run serve …

【力扣】三角形最小路径和

目录 题目 例子 示例 1&#xff1a; 示例 2&#xff1a; 前言 思路 思想 代码 调用的函数 主函数 所有代码 力扣提交的代码 运行结果 小结 题目 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结…

分布式事务基础理论

基础概念 什么是事务 什么是事务&#xff1f;举个生活中的例子&#xff1a;你去小卖铺买东西&#xff0c;“一手交钱&#xff0c;一手交货”就是一个事务的例子&#xff0c;交钱和交货必 须全部成功&#xff0c;事务才算成功&#xff0c;任一个活动失败&#xff0c;事务将撤销…

BUU 加固题 AWDP Fix 持续更新中

BUU Ezsql 首先连接上ssh。输入账号密码。 到/var/www/html目录下&#xff0c;源码在里面。 主要是看index.php文件。 <?php error_reporting(0); include dbConnect.php; $username $_GET[username]; $password $_GET[password]; if (isset($_GET[username]) &&am…

shared library

原文、 shared library compatible vs incompatible compatible library 函数的工作场景没有变化 所有的函数对全局变量和返回参数产生相同的影响所有的函数继续返回相同的结果值提升性能 fix bugs 没有api 被删除可以有新的api加入 export 的结构体没有变化 违反以上各条的…

c++八股day2-虚函数表和虚函数表指针的创建时机

虚函数表和虚函数表指针的创建时机。 背景&#xff1a;用来实现多态&#xff08;包括静态多态和动态多态&#xff09;&#xff0c;多态的原理就是虚函数表和虚函数表指针 虚函数表的创建时机&#xff1a; a.什么时候生成的&#xff1f;编译器编译的时候声生成的&#xff0c;…

筑梦未来,与“EYE”同行——蔡司镜片X肇庆爱尔眼科医院走进石群小学

不知不觉&#xff0c;蔡司光学这项传递护眼理念、营造公益氛围的助童活动已步入第十个年头。从一开始的“孤军奋战”&#xff0c;到现如今拥有汇聚眼视光领域同行的社会号召力&#xff0c;品牌为青少年近视管理方案绘就了清晰的发展蓝图&#xff0c;旨在用蔡司镜片帮助广大青少…

Java(运算符+循环)万字超详细介绍 (囊括了按位,异或,for,while等基础和疑难知识)

【本节目标1】熟练掌握运算符 【本章目标2】熟练掌握循环 万字讲解&#xff0c;十分详细&#xff0c;有大量&#xff08;简单&#xff09;代码帮助理解和大量的&#xff08;简单&#xff09;举例与总结。 1.运算符 1.什么是运算符 计算机最基本的用途之一就是执行数学运算…

shopee——排序模型AUC还能涨吗?

文章目录 CBMRMultiCBMRSample Weight Assignment多任务推荐模型 CBMR MultiCBMR Sample Weight Assignment Click-aware Structure Transfer with Sample Weight Assignment for Post-Click Conversion Rate Estimation 每个用户的top-k 邻居每个商品的top-k 邻居平滑处理并构…

Windows【工具 04】WinSW官网使用说明及实例分享(将exe和jar注册成服务)实现服务器重启后的服务自动重启

官方Github&#xff1b;官方下载地址。没有Git加速的话很难下载&#xff0c;分享一下发布日期为2023.01.29的当前最新稳定版v2.12.0网盘连接。 包含文件&#xff1a; WinSW-x64.exesample-minimal.xmlsample-allOptions.xml 链接&#xff1a;https://pan.baidu.com/s/1sN3hL5H…