09 | JpaSpecificationExecutor 解决了哪些问题
QueryByExampleExecutor用法
QueryByExampleExecutor(QBE)是一种用户友好的查询技术,具有简单的接口,它允许动态查询创建,并且不需要编写包含字段名称的查询。
下面是一个 UML 图,你可以看到 QueryByExampleExecutor 是 JpaRepository 的父接口,也就是 JpaRespository 里面继承了 QueryByExampleExecutor 的所有方法。

图一:Repository 类图
QBE 的基本语法
QBE 的基本语法可以分为下述几种。
复制代码
public interface QueryByExampleExecutor<T> { //根据“实体”查询条件,查找一个对象
<S extends T> 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);
}
你可以看到这几个语法其实差不多,下面我们用 Page`` findAll 写一个分页查询的例子,看一下效果。
QueryByExampleExecutor 的使用案例
我们还用先前的 User 实体和 UserAddress 实体,并把 User 变丰富一点,这样方便测试。两个实体关键代码如下。
复制代码
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "address")
public class User implements Serializable {@Id@GeneratedValue(strategy= GenerationType.AUTO)private Long id;private String name;private String email;@Enumerated(EnumType.STRING)private SexEnum sex;private Integer age;private Instant createDate;private Date updateDate;@OneToMany(mappedBy = "user",fetch = FetchType.EAGER,cascade = {CascadeType.ALL})private List<UserAddress> address;
}
enum SexEnum {BOY,GIRL
}
//User实体我们扩充了一些字段去了不同的类型,方便测试
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "user")
public class UserAddress {@Id@GeneratedValue(strategy= GenerationType.AUTO)private Long id;private String address;@ManyToOne(cascade = CascadeType.ALL)@JsonIgnoreprivate User user;
}
//UserAddress基本上不变
可以看出两个实体我们加了些字段。UserAddressRepository 继承 JpaRepository,从而也继承了 QueryByExampleExceutor 里面的方法,如下所示。
复制代码
public interface UserAddressRepository extends JpaRepository<UserAddress,Long> {
}
那么我们写一个测试用例,来熟悉一下 QBE 的语法,看一下完整的测试用例的写法。
复制代码
package com.example.jpa.example1;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.annotation.Rollback;
import javax.transaction.Transactional;
import java.time.Instant;
import java.util.Date;
@DataJpaTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserAddressRepositoryTest {@Autowiredprivate UserAddressRepository userAddressRepository;private Date now = new Date();/*** 负责添加数据,假设数据库里面已经有的数据*/@BeforeAll@Rollback(false)@Transactionalvoid init() {User user = User.builder().name("jack").email("123456@126.com").sex(SexEnum.BOY).age(20).createDate(Instant.now()).updateDate(now).build();userAddressRepository.saveAll(Lists.newArrayList(UserAddress.builder().user(user).address("shanghai").build(),UserAddress.builder().user(user).address("beijing").build()));}@Test@Rollback(false)public void testQBEFromUserAddress() throws JsonProcessingException {User request = User.builder().name("jack").age(20).email("12345").build();UserAddress address = UserAddress.builder().address("shang").user(request).build();ObjectMapper objectMapper = new ObjectMapper();
// System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(address)); //可以打印出来看看参数是什么
//创建匹配器,即如何使用查询条件ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("user.email", ExampleMatcher.GenericPropertyMatchers.startsWith()).withMatcher("address", ExampleMatcher.GenericPropertyMatchers.startsWith());Page<UserAddress> u = userAddressRepository.findAll(Example.of(address,exampleMatcher), PageRequest.of(0,2));System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(u));}
}
其中,方法 testQBEFromUserAddress 负责测试 QBE,那么假设我们要写 API 的话,前端给我们的查询参数如下。
复制代码
{"id" : null,"address" : "shang","user" : {"id" : null,"name" : "jack","email" : "12345","sex" : null,"age" : 20,"createDate" : null,"updateDate" : null}
}
想要满足 email 前缀匹配、地址前缀匹配的动态查询条件,我们可以跑一下测试用例看一下结果。
复制代码
Hibernate: select useraddres0_.id as id1_2_, useraddres0_.address as address2_2_, useraddres0_.user_id as user_id3_2_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where user1_.age=20 and (user1_.email like ? escape ?) and user1_.name=? and (useraddres0_.address like ? escape ?) limit ?
2020-09-20 23:04:24.391 TRACE 62179 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [12345%]
2020-09-20 23:04:24.391 TRACE 62179 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [CHAR] - [\]
2020-09-20 23:04:24.392 TRACE 62179 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [jack]
2020-09-20 23:04:24.392 TRACE 62179 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [shang%]
2020-09-20 23:04:24.393 TRACE 62179 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [CHAR] - [\]
其中我们可以看到,传进来的参数和最终执行的 SQL,还挺符合我们的预期的,所以我们也能得到正确响应的查询结果,如下图:

也就是一个地址带一个 User 结果。
那么接下来我们分析一下 Example 这个参数,看看它具体的语法是什么。
Example 语法详解
关于 Example 的语法,我们直接看一下它的源码吧,比较简单。
复制代码
public interface Example<T> {static <T> Example<T> of(T probe) {return new TypedExample<>(probe, ExampleMatcher.matching());}static <T> Example<T> of(T probe, ExampleMatcher matcher) {return new TypedExample<>(probe, matcher);}//实体参数T getProbe();//匹配器ExampleMatcher getMatcher();//回顾一下我们上一课时讲解的类型,这个是返回实体参数的Class Type;@SuppressWarnings("unchecked")default Class<T> getProbeType() {return (Class<T>) ProxyUtils.getUserClass(getProbe().getClass());}
}
而 TypedExample 这个类不是 public 的,看如下源码。
复制代码
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
@Getter
class TypedExample<T> implements Example<T> {private final @NonNull T probe;private final @NonNull ExampleMatcher matcher;
}
其中我们发现三个类:Probe、ExampleMatcher 和 Example,分别做如下解释:
- Probe:这是具有填充字段的域对象的实际实体类,即查询条件的封装类(又可以理解为查询条件参数),必填。
- ExampleMatcher:ExampleMatcher 有关如何匹配特定字段的匹配规则,它可以重复使用在多个实例中,必填。
- Example:Example 由 Probe 探针和 ExampleMatcher 组成,它用于创建查询,即组合查询参数和参数的匹配规则。
通过 Example 的源码,我们发现想创建 Example 的话,只有两个方法:
- static
Exampleof(T probe):需要一个实体参数,即查询的条件。而里面的 ExampleMatcher 采用默认的 ExampleMatcher.matching(); 表示忽略 Null,所有字段采用精准匹配。 - static
Exampleof(T probe, ExampleMatcher matcher):需要两个参数构建 Example,也就表示了 ExampleMatcher 自由组合规则,正如我们上面的测试用例里面的代码一样。
那么现在又遇到个类:ExampleMatcher,我们分析一下它的语法。
ExampleMatcher 语法分析
我们通过分析 ExampleMatcher 的源码来分析一下其用法。
首先打开 Structure 视图,看看里面对外暴露的方法都有哪些。

通过 Structure 视图可以很容易地发现,我们要关心的方法都是这些 public 类型的返回 ExampleMatcher 的方法,那么我们把这些方法搞明白了是不是就可以掌握其详细用法了呢?下面看看它的实现类。

TypedExampleMatcher 不是 public 类型的,所以我们可以基本上不用看了,主要看一下接口里面给我们暴露了哪些实例化方法。
初始化 ExampleMatcher 实例的方法
查看初始化 ExampleMatcher 实例的方法时,我们发现只有如下三个。
先看一下前两个方法:
复制代码
//默认matching方法
static ExampleMatcher matching() {return matchingAll();
}
//matchingAll,默认的方法
static ExampleMatcher matchingAll() {return new TypedExampleMatcher().withMode(MatchMode.ALL);
}
我们看到上面的两个方法所表达的意思是一样的,只不过一个是默认,一个是方法名上面有语义的。两者采用的都是 MatchMode.ALL 的模式,即 AND 模式,生成的 SQL 为如下形式:
复制代码
Hibernate: select useraddres0_.id as id1_2_, useraddres0_.address as address2_2_, useraddres0_.user_id as user_id3_2_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where user1_.age=20 and user1_.name=? and (user1_.email like ? escape ?) and (useraddres0_.address like ? escape ?) limit ?
可以看到,这些查询条件之间都是 AND 的关系。
我们再看一下方法三:
复制代码
static ExampleMatcher matchingAny() {return new TypedExampleMatcher().withMode(MatchMode.ANY);
}
第三个方法和前面两个方法的区别在于:第三个 MatchMode.ANY,表示查询条件是 or 的关系,我们看一下 SQL:
复制代码
Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.address like ? escape ? or user1_.age=20 or user1_.email like ? escape ? or user1_.name=?
以上就是三个初始化 ExampleMatcher 实例的方法,你在运用中需要注意 and 和 or 的关系。
那么,我们再看一下 ExampleMatcher 语法给我们暴露的方法有哪些。
ExampleMatcher 语法给我们暴露的方法
忽略大小写
关于忽略大小写,我们看下代码:
复制代码
//默认忽略大小写的方式,默认 False。
ExampleMatcher withIgnoreCase(boolean defaultIgnoreCase);
//提供了一个默认的实现方法,忽略大小写;
default ExampleMatcher withIgnoreCase() {return withIgnoreCase(true);
}
//哪些属性的paths忽略大小写,可以指定多个参数;
ExampleMatcher withIgnoreCase(String... propertyPaths);
NULL 值的 property 怎么处理
暴露的 Null 值处理方式如下:
复制代码
ExampleMatcher withNullHandler(NullHandler nullHandler);
我们直接看参数 NullHandler枚举值即可,有两个可选值:INCLUDE(包括)、IGNORE(忽略),其中要注意:
- 标识作为条件的实体对象中,一个属性值(条件值)为 Null 时,是否参与过滤;
- 当该选项值是 INCLUDE 时,表示仍参与过滤,会匹配数据库表中该字段值是 Null 的记录;
- 若为 IGNORE 值,表示不参与过滤。
复制代码
//提供一个默认实现方法,忽略 NULL 属性;
default ExampleMatcher withIgnoreNullValues() {return withNullHandler(NullHandler.IGNORE);
}
//把 NULL 属性值作为查询条件
default ExampleMatcher withIncludeNullValues() {return withNullHandler(NullHandler.INCLUDE);
}
到这里看一下,把 NULL 属性值作为查询条件,会执行什么样的 SQL:
复制代码
Hibernate: select useraddres0_.id as id1_2_, useraddres0_.address as address2_2_, useraddres0_.user_id as user_id3_2_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where (user1_.id is null) and (user1_.update_date is null) and user1_.age=20 and (user1_.create_date is null) and lower(user1_.name)=? and (lower(user1_.email) like ? escape ?) and (user1_.sex is null) and (lower(useraddres0_.address) like ? escape ?) and (useraddres0_.id is null) limit ?
这样就会导致我们一条数据都查不出来了。
忽略某些 Paths,不参加查询条件
复制代码
//忽略某些属性列表,不参与查询过滤条件。
ExampleMatcher withIgnorePaths(String... ignoredPaths);
字符串字段默认的匹配规则
复制代码
ExampleMatcher withStringMatcher(StringMatcher defaultStringMatcher);
关于默认字符串的匹配方式,枚举类型有 6 个可选值,DEFAULT(默认,效果同 EXACT)、EXACT(相等)、STARTING(开始匹配)、ENDING(结束匹配)、CONTAINING(包含,模糊匹配)、REGEX(正则表达式)。
字符串匹配规则,我们和 JPQL 对应到一起举例,如下表所示:

相关代码如下:
复制代码
ExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher);
这里显示的是指定某些属性的匹配规则,我们看一下 GenericPropertyMatcher 是什么东西,它都提供了哪些方法。
如下图,基本可以看出来都是针对字符串属性提供的匹配规则,也就是可以通过这个方法定制不同属性的 StringMatcher 规则。

到这里,语法部分我们就学习完了,下面看一个完整的例子感受一下。
完整的例子
下面是一个关于咱们上面所说的暴露的方法的使用的例子,你可以跟着我的步骤自己动手练习一下。
复制代码
//创建匹配器,即如何使用查询条件
ExampleMatcher exampleMatcher = ExampleMatcher//采用默认and的查询方式.matchingAll()//忽略大小写.withIgnoreCase()//忽略所有null值的字段.withIgnoreNullValues().withIgnorePaths("id","createDate")//默认采用精准匹配规则.withStringMatcher(ExampleMatcher.StringMatcher.EXACT)//级联查询,字段user.email采用字符前缀匹配规则.withMatcher("user.email", ExampleMatcher.GenericPropertyMatchers.startsWith())//特殊指定address字段采用后缀匹配.withMatcher("address", ExampleMatcher.GenericPropertyMatchers.endsWith());
Page<UserAddress> u = userAddressRepository.findAll(Example.of(address,exampleMatcher), PageRequest.of(0,2));
这时候可能会有同学问了,我是怎么知道默认值的呢?我们直接看类的构造方法就可以了,如下所示:

从源码中我们可以看到,实现类的构造方法只有一个,就是“赋值默认”的方式。下面我整理了一些在使用这个语法时需要考虑的细节。
ExampleExceutor 使用中需要考虑的因素
- Null 值的处理:当某个条件值为 Null 时,是应当忽略这个过滤条件,还是应当去匹配数据库表中该字段值是 Null 的记录呢?
- 忽略某些属性值:一个实体对象,有许多个属性,是否每个属性都参与过滤?是否可以忽略某些属性?
- 不同的过滤方式:同样是作为 String 值,可能“姓名”希望精确匹配,“地址”希望模糊匹配,如何做到?
那么接下来我们分析一下源码看看其原理,说了这么半天,它到底和 JpaSpecificationExecutor 什么关系呢?我们接着看。
QueryByExampleExecutor 源码分析
怎么分析源码也很简单,我们看一下上面的我们 findAll 的方法调用之处。

从而找到 findAll 方法的实现类,如下所示:

通过 Debug 断点我们可以看到,我们刚才组合出来的 Example 对象,这个时候被封装成了 ExampleSpecification 对象,那么我们接着往下看方法里面的关键内容。
复制代码
TypedQuery<S> query = getQuery(new ExampleSpecification<>(example, escapeCharacter), probeType, pageable);
getQuery 方法是创建 Query 的关键,因为它里面做了条件的转化逻辑。那么我们再看一下参数 ExampleSpecification 的源码,发现它是接口 Specification 的实现类,并且是非公开的实现类,可以通过接口对外暴露 and、or、not、where 等组合条件的查询条件。

我们接着看上面的 getQuery 方法的实现,可以看到接收的参数是 Specification``接口,所以不用关心实现类是什么。

我们接着再看这个断点的 getQuery 方法:

里面有一段代码会调用 applySpecificationToCriteria 生成 root,并由 Root 作为参数生成 Query,从而交给 EM(EntityManager)进行查询。
我们再来看一下关键的 applySpecificationToCriteria 方法。

根据 Specification 调用 toPredicate 方法,生成 Predicate,从而实现查询需求。
现在我们已经对 QueryByExampleExecutor 的用法和实现原理基本掌握了,我们再来看一个十分相似的接口:JpaSpecificationExecutor 是干什么用的。
JpaSpecificationExecutor 接口结构
正如我们开篇提到的【图一:Repository 类图】,JpaSpecificationExecutor 是 JPA 里面的另一个接口分支。我们先来看看它的基本语法。

我们通过查看 JpaSpecificationExecutor 的 Structure 图会发现,方法就有这么几个,细心的同学这个时候会发现它的参数 Specification,正是我们分析 QueryByExampleExecutor 的原理时候使用的 Specification。
那么 JpaSpecificationExecutor 帮我们解决了哪些问题呢?
JpaSpecificationExecutor 解决了哪些问题
- 我们通过 QueryByExampleExecutor 的使用方法和原理分析,不难发现,JpaSpecificationExecutor 的查询条件 Specification 十分灵活,可以帮我们解决动态查询条件的问题,正如 QueryByExampleExecutor 的用法一样;
- 它提供的 Criteria API 的使用封装,可以用于动态生成 Query 来满足我们业务中的各种复杂场景;
- 既然QueryByExampleExecutor 能利用 Specification 封装成框架,我们是不是也可以利用 JpaSpecificationExecutor 封装成框架呢?这样就学会了举一反三。
相关文章:
09 | JpaSpecificationExecutor 解决了哪些问题
QueryByExampleExecutor用法 QueryByExampleExecutor(QBE)是一种用户友好的查询技术,具有简单的接口,它允许动态查询创建,并且不需要编写包含字段名称的查询。 下面是一个 UML 图,你可以看到 QueryByExam…...
Linux命令(93)之su
linux命令之su 1.su介绍 linux命令su用于变更为其它使用者的身份,如root用户外,需要输入使用者的密码 2.su用法 su [参数] user su参数 参数说明-c <command>执行指定的命令,然后切换回原用户-切换到目标用户的环境变量 3.实例 3…...
1.HTML-HTML解决中文乱码问题
题记 下面是html文件解决中文乱码的方法 方法一 在 HTML 文件的 <head> 标签中添加 <meta charset"UTF-8">,确保文件以 UTF-8 编码保存 <head> <meta charset"UTF-8"> <!-- 其他标签和内容 --> </head> --…...
Vue3 + Nodejs 实战 ,文件上传项目--实现拖拽上传
目录 1.拖拽上传的剖析 input的file默认拖动 让其他的盒子成为拖拽对象 2.处理文件的上传 处理数据 上传文件的函数 兼顾点击事件 渲染已处理过的文件 测试效果 3.总结 博客主页:専心_前端,javascript,mysql-CSDN博客 系列专栏:vue3nodejs 实战-…...
Windows:VS Code IDE安装ESP-IDF【保姆级】
物联网开发学习笔记——目录索引 参考: VS Code官网:Visual Studio Code - Code Editing. Redefined 乐鑫官网:ESP-IDF 编程指南 - ESP32 VSCode ESP-ID Extension Install 一、前提条件 Visual Studio Code IDE安装ESP-IDF扩展…...
Hadoop3教程(十一):MapReduce的详细工作流程
文章目录 (94)MR工作流程Map阶段Reduce阶段 参考文献 (94)MR工作流程 本小节将展示一下整个MapReduce的全工作流程。 Map阶段 首先是Map阶段: 首先,我们有一个待处理文本文件的集合; 客户端…...
测试中Android与IOS分别关注的点
目录 1、自身不同点 2、测试注重点 3、其他测试点 主要从本身系统的不同点、系统造成的不同点、和注意的测试点做总结 1、自身不同点 研发商:Adroid是google公司做的手机系统,IOS是苹果公司做的手机系统 开源程度:Android是开源的&a…...
NLG(自然语言生成)评估指标介绍
诸神缄默不语-个人CSDN博文目录 本文介绍自然语言生成任务中的各种评估指标。 因为我是之前做文本摘要才接触到这一部分内容的,所以本文也是文本摘要中心。 持续更新。 文章目录 1. 常用术语2. ROUGE (Recall Oriented Understudy for Gisting Evaluation)1. 计算…...
苍穹外卖(七) Spring Task 完成订单状态定时处理
Spring Task 完成订单状态定时处理, 如处理支付超时订单 Spring Task介绍 Spring Task 是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。 应用场景: 信用卡每月还款提醒 火车票售票系统处理未支付订单 入职纪念日为用户发送通知 点外…...
【探索Linux】—— 强大的命令行工具 P.11(基础IO,文件操作)
阅读导航 前言一、C语言的文件操作二、C的文件操作三、Linux系统文件操作(I/O接口)1. open()⭕传入多个打开方式(按位或操作将不同的标志位组合在一起) 2. write()3. read()4. close()5. lseek() 温馨提示 前言 前面我们讲了C语言…...
前端练习项目(附带页面psd图片及react源代码)
一、前言 相信很多学完前端的小伙伴都想找个前端项目练练手,检测自己的学习成果。但是现在很多项目市面上都烂大街了。今天给大家推荐一个全新的项目——电子校园 项目位置:https://github.com/v5201314/eSchool 二、项目介绍(部分页面展示)ÿ…...
【从零开始学习Redis | 第三篇】在Java中操作Redis
前言: 本文算是一期番外,介绍一下如何在Java中使用Reids ,而其实基于Java我们有很多的开源框架可以用来操作redis,而我们今天选择介绍的是其中比较常用的一款:Spring Data Redis 目录 前言: Spring Data…...
vim、gcc/g++、make/Makefile、yum、gdb
vim、gcc/g、make/Makefile、yum、gdb 一、Linux编辑器vim1、简介2、三种模式的概念(1)正常/普通/命令模式(Normal mode)(2)插入模式(Insert mode)(3)末行/底行模式(last line mode) 3、三种模式的切换4、正…...
2022最新版-李宏毅机器学习深度学习课程-P13 局部最小值与鞍点
一、优化失败的原因 局部最小值?鞍点? 二、数学推导分析 用泰勒公式展开 一项与梯度(L的一阶导)有关,一项与海赛矩阵(L的二阶导)有关 海瑟矩阵 VTHV通过海瑟矩阵的性质可以转为判断H是否是正…...
ARM架构的基本知识
ARM两种授权 体系结构授权, 一种硬件规范, 用来约定指令集, 芯片内部体系结构(内存管理, 高速缓存管理), 只约定每一条指令的格式, 行为规范, 参数, 客户根据这个规范自行设计与之兼容的处理器处理IP授权, ARM公司根据某个版本的体系结构设计处理器, 再把处理器设计方案授权给…...
网络安全(黑客技术)——如何高效自学
前言 前几天发布了一篇 网络安全(黑客)自学 没想到收到了许多人的私信想要学习网安黑客技术!却不知道从哪里开始学起!怎么学?如何学? 今天给大家分享一下,很多人上来就说想学习黑客,…...
云原生场景下高可用架构的最佳实践
作者:刘佳旭(花名:佳旭),阿里云容器服务技术专家 引言 随着云原生技术的快速发展以及在企业 IT 领域的深入应用,云原生场景下的高可用架构,对于企业服务的可用性、稳定性、安全性越发重要。通…...
图论-最短路径算法-弗洛伊德算法与迪杰斯特拉算法
弗洛伊德算法: 弗洛伊德算法本质是动态规划,通过添加点进如可选择的点组成的集合的同时更新所有点之间的距离,从而得到每两个点之间的最短距离。 初始化: 创建一个二维数组 dist,其中 dist[i][j] 表示从节点 i 到节点…...
[23] IPDreamer: Appearance-Controllable 3D Object Generation with Image Prompts
pdf Text-to-3D任务中,对3D模型外观的控制不强,本文提出IPDreamer来解决该问题。在NeRF Training阶段,IPDreamer根据文本用ControlNet生成参考图,并将参考图作为Zero 1-to-3的控制条件,用基于Zero 1-to-3的SDS损失生成…...
深入理解React中的useEffect钩子函数
引言: React是一种流行的JavaScript库,它通过组件化和声明式编程的方式简化了前端开发。在React中,一个核心概念是组件的生命周期,其中包含了许多钩子函数,用于管理组件的不同阶段。其中之一就是useEffect钩子函数&…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
