当前位置: 首页 > news >正文

Redis经典五大类型源码及底层实现(一)

  • 👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家
  • 📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术
  • 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
  • 🍂博主正在努力完成2023计划中:源码溯源,一探究竟
  • 📝联系方式:nhs19990716,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬👀

文章目录

  • Redis经典五大类型源码及底层实现
    • 经典面试题
    • redis源码
    • 核心部分
      • 数据结构
      • Redis数据库的实现
      • Redis服务端和客户端实现
      • Redis字典数据库KV键值对是什么?
      • 10大类型
      • 上帝视角
      • RedisObject结构体
        • struct结构体
        • 字典、KV是什么?
        • redisObject + Redis数据类型 + Redis所有编码方式(底层实现)三者之间的关系
    • 五大数据结构C语言源码分析
      • redis6.0.5
      • Redis7
      • 源码分析总体数据结构大纲
      • 从set hello world说起
      • redisObject结构的作用
        • RedisObject各个字段的含义
      • 五大经典结构解析
        • String数据类型介绍
          • 3大物理编码方式
            • int
            • embstr
            • raw
          • 3大物理编码案例
          • SDS简单动态字符串
          • Redis为什么要重新设计一个SDS数据结构呢?
          • 源码分析
            • 结论
        • Hash数据结构介绍
          • Redis6
            • 案例
            • 源码分析
            • t_hash.c
            • OBJ_ENCODING_HT编码解析
            • ziplist
            • 明明已经有链表了出来一个压缩链表?
            • ziplist总结

Redis经典五大类型源码及底层实现

经典面试题

Redis的跳跃列表了解吗?这个数据结构有什么特点

redis项目里面怎么用?redis的数据结构都了解那些?

redis的zset底层实现,说了压缩列表和跳表,问这样设计的优缺点,只说了优点,缺点没说出来

redis的跳表说一下,解决了哪些问题,时间复杂度和空间复杂度如何

其实阅读源码90%是没有太大意义的,完全是为了面试,但是10%是因为大厂自己的内部中间件,比如贵公司自己内部redis重构,阿里云redis,美团tair,滴滴kedrs等等

redis源码

在这里插入图片描述

https://github.com/redis/redis

而对应的源码分析的书籍有

在这里插入图片描述

在这里插入图片描述

核心部分

数据结构

  • 简单动态字符串sds.c
  • 整数集合intset.c
  • 压缩列表ziplist.c
  • 快速链表quicklist.c
  • listpack
  • 字典dict.c

Redis数据库的实现

数据库底层实现db.c 和 持久化rdb.c 、aof.c

Redis服务端和客户端实现

  • 事件驱动ae.c 和 ae_epoll.c
  • 网络连接anet.c 和 networking.c
  • 服务端程序 server.c
  • 客户端程序redis-cli.c

Redis字典数据库KV键值对是什么?

redis是key-value存储系统,key一般是String类型的字符串对象,value类型则为redis对象(redisObject),value可以是字符串对象,也可以是集合数据类型的对象,比如List对象,Hash对象,set对象和zset对象。

在这里插入图片描述

10大类型

String

List

Hash

Set

Zset

bitmap 实质是String

hyperloglog 实质是String

GEO 实质是Zset

Stream 实质是Stream

BITFIELD 看具体key

在这里插入图片描述

上帝视角

在这里插入图片描述

RedisObject结构体

redis定义了redisobject结构体来表示string、hash、list、set、zset等数据结构

struct结构体

在这里插入图片描述

Redis中每个对象都是一个redisobject

字典、KV是什么?

每个键值对都会有一个dictEntry

在这里插入图片描述

这些键值对是如何保存进Redis并进行读取操作,O(1)复杂度的

在这里插入图片描述

redisObject + Redis数据类型 + Redis所有编码方式(底层实现)三者之间的关系

在这里插入图片描述

五大数据结构C语言源码分析

redis6.0.5

redis6之前,老版本

在这里插入图片描述

Redis7

在这里插入图片描述

源码分析总体数据结构大纲

程序员写代码时脑子底层思维

在这里插入图片描述

在这里插入图片描述

从set hello world说起

set hello word为例,因为Redis是KV键值对的数据库,每个键值对都会有一个dictEntry(源码位置:dict.h),

里面指向了key和value的指针,next 指向下一个 dictEntry。

key 是字符串,但是 Redis 没有直接使用 C 的字符数组,而是存储在redis自定义的 SDS中。

value 既不是直接作为字符串存储,也不是直接存储在 SDS 中,而是存储在redisObject 中

实际上五种常用的数据类型的任何一种,都是通过 redisObject 来存储的。

在这里插入图片描述

看看类型
type hello
String看看编码
Object encoding hello
embstr

redisObject结构的作用

为了便于操作,Redis采用redisObjec结构来统一五种不同的数据类型,这样所有的数据类型就都可以以相同的形式在函数间传递而不用使用特定的类型结构。同时,为了识别不同的数据类型,redisObjec中定义了type和encoding字段对不同的数据类型加以区别。简单地说,redisObjec就是string、hash、list、set、zset的父类,可以在函数间传递时隐藏具体的类型信息,所以作者抽象了redisObjec结构来到达同样的目的。

在这里插入图片描述

RedisObject各个字段的含义

在这里插入图片描述

1 4位的type表示具体的数据类型

2 4位的encoding表示该类型的物理编码方式见下表,同一种数据类型可能有不同的编码方式。

(比如String就提供了3种:int embstr raw)

3 lru字段表示当内存超限时采用LRU算法清除内存中的对象。

4 refcount表示对象的引用计数。

5 ptr指针指向真正的底层数据结构的指针。

在这里插入图片描述

例如

set age 17

在这里插入图片描述

type类型
encoding编码,此处是数字类型
lru最近被访问的时间
refcount等于1,表示当前对象被引用的次数
ptrvalue值是多少,当前就是17

五大经典结构解析

各个类型的数据结构的编码映射和定义

在这里插入图片描述

Debug Object key

在这里插入图片描述

开启后

在这里插入图片描述

Value at: 内存地址

refcount: 引用次数

encoding: 物理编码类型

serializedlength: 序列化后的长度(注意这里的长度是序列化后的长度,保存为rdb文件时使用了该算法,不是真正存贮在内存的大小),会对字串做一些可能的压缩以便底层优化

lru:记录最近使用时间戳

lru_seconds_idle:空闲时间

在这里插入图片描述

String数据类型介绍
3大物理编码方式

RedisObjectt内部对应的3大物理编码

在这里插入图片描述

int

保存long型(长整型)的64位(8个字节)的有符号整数

在这里插入图片描述

补充:只有整数才会使用int,如果是浮点数,Redis内部其实先将浮点数转化为字符串值,然后再保存。

embstr

代表embstr格式的SDS 简单动态字符串,保存长度小于44字节的字符串,顾名思义,表示嵌入式的String

raw

保存长度大于44字节的字符串

3大物理编码案例

在这里插入图片描述

假如现在展现一个字符串:Redis

在这里插入图片描述

Redis没有直接复用C语言的字符串,而是新建了属于自己的结构-----SDS

在Redis数据库里,包含字符串值的键值对都是由SDS实现的(Redis中所有的键都是由字符串对象实现的即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现)。

在这里插入图片描述

SDS简单动态字符串

sds.h源码分析

在这里插入图片描述

在这里插入图片描述

Redis中字符串的实现,SDS有多种结构(sds.h):

sdshdr5、(2^5=32byte)

sdshdr8、(2 ^ 8=256byte)

sdshdr16、(2 ^ 16=65536byte=64KB)

sdshdr32、 (2 ^ 32byte=4GB)

sdshdr64,2的64次方byte=17179869184G用于存储不同的长度的字符串。

len 表示 SDS 的长度,使我们在获取字符串长度的时候可以在 O(1)情况下拿到,而不是像 C 那样需要遍历一遍字符串。

alloc 可以用来计算 free 就是字符串已经分配的未使用的空间,有了这个值就可以引入预分配空间的算法了,而不用去考虑内存分配的问题。

buf 表示字符串数组,真存数据的。

在这里插入图片描述

Redis为什么要重新设计一个SDS数据结构呢?

C语言没有Java里面的String类型,只能是靠自己的char[]来实现,字符串在 C 语言中的存储方式,想要获取 「Redis」的长度,需要从头开始遍历,直到遇到 ‘\0’ 为止。所以,Redis 没有直接使用 C 语言传统的字符串标识,而是自己构建了一种名为简单动态字符串 SDS(simple dynamic string)的抽象类型,并将 SDS 作为 Redis 的默认字符串。

C语言SDS
字符串长度处理需要从头开始遍历,直到遇到 ‘\0’ 为止,时间复杂度O(N)记录当前字符串的长度,直接读取即可,时间复杂度 O(1)
内存重新分配分配内存空间超过后,会导致数组下标越级或者内存分配溢出空间预分配 SDS 修改后,len 长度小于 1M,那么将会额外分配与 len 相同长度的未使用空间。如果修改后长度大于 1M,那么将分配1M的使用空间。惰性空间释放 有空间分配对应的就有空间释放。SDS 缩短时并不会回收多余的内存空间,而是使用 free 字段将多出来的空间记录下来。如果后续有变更操作,直接使用 free 中记录的空间,减少了内存的分配。
二进制安全二进制数据并不是规则的字符串格式,可能会包含一些特殊的字符,比如 ‘\0’ 等。前面提到过,C中字符串遇到 ‘\0’ 会结束,那 ‘\0’ 之后的数据就读取不上了根据 len 长度来判断字符串结束的,二进制安全的问题就解决了
源码分析

set k1 v1 底层发生了什么?调用关系

在这里插入图片描述

三大物理编码方式

在这里插入图片描述

int编码

在这里插入图片描述

set k1 123

命令示例: set k1 123

当字符串键值的内容可以用一个64位有符号整形来表示时,Redis会将键值转化为long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。内部的内存结构表示如下:

在这里插入图片描述

Redis 启动时会预先建立 10000 个分别存储 0~9999 的 redisObject 变量作为共享对象,这就意味着如果 set字符串的键值在 0~10000 之间的话,则可以

直接指向共享对象 而不需要再建立新对象,此时键值不占空间!

set k1 123

set k2 123

接下来就很类似Integer,如果是128以内的话,那么常量池中就存在

在这里插入图片描述

redis源代码:server.h,笔记下面还有

在这里插入图片描述

redis6源代码:object.c笔记下面还有

在这里插入图片描述

redis7源代码:object.c笔记下面还有

在这里插入图片描述

EMBSTR编码格式

在这里插入图片描述

set k1 abc

redis源代码:object.c

在这里插入图片描述

对于长度小于 44的字符串,Redis 对键值采用OBJ_ENCODING_EMBSTR 方式,EMBSTR 顾名思义即:embedded string,表示嵌入式的String。从内存结构上来讲 即字符串 sds结构体与其对应的 redisObject 对象分配在同一块连续的内存空间,字符串sds嵌入在redisObject对象之中一样。

在这里插入图片描述

进一步createEmbeddedStringObject方法

redis源代码:object.c

从图中也可以看出,内存相当紧凑,没有重新分配空间

在这里插入图片描述

RAW编码格式

在这里插入图片描述

set k1 大于44长度的一个字符串,随便写

在这里插入图片描述

当字符串的键值为长度大于44的超长字符串时,Redis 则会将键值的内部编码方式改为OBJ_ENCODING_RAW格式,这与OBJ_ENCODING_EMBSTR编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续了

在这里插入图片描述

明明没有超过阈值,为什么变成raw了?

在这里插入图片描述

判断不出来,就取最大Raw

转变逻辑图

在这里插入图片描述

结论

只有整数才会使用 int,如果是浮点数, Redis 内部其实先将浮点数转化为字符串值,然后再保存。

embstr 与 raw 类型底层的数据结构其实都是 SDS (简单动态字符串,Redis 内部定义 sdshdr 一种结构)。

那这两者的区别见下图:

1 intLong类型整数时,RedisObject中的ptr指针直接赋值为整数数据,不再额外的指针再指向整数了,节省了指针的空间开销。
2 embstr当保存的是字符串数据且字符串小于等于44字节时,embstr类型将会调用内存分配函数,只分配一块连续的内存空间,空间中依次包含 redisObject 与 sdshdr 两个数据结构,让元数据、指针和SDS是一块连续的内存区域,这样就可以避免内存碎片
3 raw当字符串大于44字节时,SDS的数据量变多变大了,SDS和RedisObject布局分家各自过,会给SDS分配多的空间并用指针指向SDS结构,raw 类型将会调用两次内存分配函数,分配两块内存空间,一块用于包含 redisObject结构,而另一块用于包含 sdshdr 结构

在这里插入图片描述

总结:Redis内部会根据用户的不同键值而使用不同的编码格式,自适应地选择较优化的内部编码格式,而这一切对用户来说完全透明

Hash数据结构介绍
Redis6

ziplist + hashtable

案例

hash-max-ziplist-entries:使用压缩列表保存时哈希集合中的最大元素个数。

hash-max-ziplist-value:使用压缩列表保存时哈希集合中单个元素的最大长度。

Hash类型键的字段个数 小于 hash-max-ziplist-entries 并且每个字段名和字段值的长度 小于 hash-max-ziplist-value 时,

Redis才会使用 OBJ_ENCODING_ZIPLIST来存储该键,前述条件任意一个不满足则会转换为 OBJ_ENCODING_HT的编码方式

在这里插入图片描述

hash-max-ziplist-entries:使用压缩列表来保存是哈希集合中最大元素个数

hash-max-ziplist-value:使用压缩列表保存时哈希集合中单个元素的最大长度

结论:

1.哈希对象保存的键值对数量小于512个

2.所有的键值对的键和值字符串长度豆小于等于64byte(一个英文字母一个字节)时用ziplist,反之用hashtable

其中ziplist升级到hashtable可以,反过来降级不可以

一旦从压缩列表转为了哈希表,Hash类型就会一直用哈希表进行保存而不会再转回压缩列表了。

在节省内存空间方面哈希表就没有压缩列表高效了。


流程:

在这里插入图片描述

源码分析
t_hash.c

在Redis中,hashtable被称为字典(dictionary),它是有一个数组 + 链表的结构

OBJ_ENCODING_HT编码解析

OBJ_ENCODING_HT 这种编码方式内部才是真正的哈希表结构,或称为字典结构,其可以实现O(1)复杂度的读写操作,因此效率很高。

在 Redis内部,从 OBJ_ENCODING_HT类型到底层真正的散列表数据结构是一层层嵌套下去的,组织关系见面图:

在这里插入图片描述

源代码:dict.h

在这里插入图片描述

在这里插入图片描述

hset命令解读:

在这里插入图片描述

在这里插入图片描述

ziplist

Ziplist 压缩列表是一种紧凑编码格式,总体思想是多花时间来换取节约空间,即以部分读写性能为代价,来换取极高的内存空间利用率,

因此只会用于 字段个数少,且字段值也较小 的场景。压缩列表内存利用率极高的原因与其连续内存的特性是分不开的。

为了节约内存而开发的,它是由连续内存块组成的顺序型数据结构,有点类似于数组

ziplist是一个经过特殊编码的双向链表,它不存储指向前一个链表节点prev和指向下一个链表节点的指针next而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能,来换取高效的内存空间利用率,节约内存,是一种时间换空间的思想。只用在字段个数少,字段值小的场景里面

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

zlentry实体结构解析:

在这里插入图片描述

在这里插入图片描述

prevlen记录了前一个节点的长度;
encoding记录了当前节点实际数据的类型以及长度
data记录了当前节点的实际数据

压缩列表zlentry节点结构:每个zlentry由前一个节点的长度、encoding和entry-data三部分组成

在这里插入图片描述

前节点:(前节点占用的内存字节数)表示前1个zlentry的长度,privious_entry_length有两种取值情况:1字节或5字节。取值1字节时,表示上一个entry的长度小于254字节。虽然1字节的值能表示的数值范围是0到255,但是压缩列表中zlend的取值默认是255,因此,就默认用255表示整个压缩列表的结束,其他表示长度的地方就不能再用255这个值了。所以,当上一个entry长度小于254字节时,prev_len取值为1字节,否则,就取值为5字节。记录长度的好处:占用内存小,1或者5个字节

enncoding:记录节点的content保存数据的类型和长度。

content:保存实际数据内容

在这里插入图片描述

privious_entry_length,encoding长度都可以根据编码方式推算,真正变化的是content,而content长度记录在encoding里 ,因此entry的长度就知道了。entry总长度 = privious_entry_length字节数+encoding字节数+content字节数

在这里插入图片描述

为什么entry这么设计?记录前一个节点的长度?

链表在内存中,一般是不连续的,遍历相对比较慢,而ziplist可以很好的解决这个问题。如果知道了当前的起始地址,因为entry是连续的,entry后一定是另一个entry,想知道下一个entry的地址,只要将当前的起始地址加上当前entry总长度。如果还想遍历下一个entry,只要继续同样的操作。

明明已经有链表了出来一个压缩链表?

1 普通的双向链表会有两个指针,在存储数据很小的情况下,我们存储的实际数据的大小可能还没有指针占用的内存大,得不偿失。ziplist 是一个特殊的双向链表没有维护双向指针:previous next;而是存储上一个 entry的长度和当前entry的长度,通过长度推算下一个元素在什么地方。牺牲读取的性能,获得高效的存储空间,因为(简短字符串的情况)存储指针比存储entry长度更费内存。这是典型的“时间换空间”。

2 链表在内存中一般是不连续的,遍历相对比较慢而ziplist可以很好的解决这个问题,普通数组的遍历是根据数组里存储的数据类型找到下一个元素的(例如int类型的数组访问下一个元素时每次只需要移动一个sizeof(int)就行),但是ziplist的每个节点的长度是可以不一样的,而我们面对不同长度的节点又不可能直接sizeof(entry),所以ziplist只好将一些必要的偏移量信息记录在了每一个节点里,使之能跳到上一个节点或下一个节点。

备注:sizeof实际上是获取了数据在内存中所占用的存储空间,以字节为单位来计数。

3 头节点里有头节点里同时还有一个参数 len,和string类型提到的 SDS 类似,这里是用来记录链表长度的。因此获取链表长度时不用再遍历整个链表,直接拿到len值就可以了,这个时间复杂度是 O(1)

ziplist总结

ziplist为了节省内存,采用了紧凑的连续存储。

ziplist是一个双向链表,可以在时间复杂度为 O(1) 下从头部、尾部进行 pop 或 push。

新增或更新元素可能会出现连锁更新现象(致命缺点导致被listpack替换)。

不能保存过多的元素,否则查询效率就会降低,数量小和内容小的情况下可以使用。

相关文章:

Redis经典五大类型源码及底层实现(一)

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…...

数据库闭包求法 附相关习题及解析

闭包就是由一个属性直接或间接推导出的所有属性的集合 以下是写的比较科学规范的闭包求解方法,设X和Y均为关系R的属性集的子集,F是R上的函数依赖集,若对R的任一属性集B,一旦X→B,必有B⊆Y,且对R的任一满足…...

idea利用JRebel插件,无需重启,实现Spring Boot项目热重载,节省开发时间和精力!

插件介绍 官方介绍 翻译过来的意思是: JRebel 是一款提高开发效率的工具,允许开发者立即重新加载代码更改。它跳过了在Java开发中常见的重新构建、重启和重新部署循环。JRebel 能够让开发者在相同的时间内完成更多工作,并且在编码时能够保持…...

学习体系结构 - AArch64内存管理

学习体系结构 - AArch64内存管理 Learn the architecture - AArch64 memory management Version 1.2 个人的英语很一般,对拿不准的翻译校准在后面添加了英文原文。 1、 概述 本指南介绍了AArch64中的内存转换,这是内存管理的关键。它解释了如何将虚拟地…...

Vue3 精通指南:如何在 setup 函数中巧妙利用 Vuex

在 Vue 3 中,如果你使用了组合式 API(Composition API),你可以通过 setup 函数来设置组件的响应式状态和逻辑。要在 setup 函数中访问 Vuex 的 $store,你可以使用 useStore 钩子,它是 Vuex 4 为 Vue 3 提供…...

Linux 服务器安全策略技巧:启用账户锁定策略

Linux 服务器安全策略技巧:启用账户锁定策略 在Linux服务器上,启用账户锁定策略是一种重要的安全措施。通过锁定账户,可以防止未经授权的访问和恶意活动。本文将介绍如何在Linux服务器上启用账户锁定策略。 什么是账户锁定策略? 账户锁定策略是一种安全措施,用于限制对…...

野火霸道-V2+3.2寸屏+FreeRTOS+LVGL移植

摘要 基于野火霸道-V23.2寸屏的开发板,下载器为STLINK分为两个版本,FreeRTOS和裸机版本 裸机 裸机准备 lvgl v8.2版本的源码野火的《触摸画板-3.2寸》与《基本定时器》的代码例程 移植 将基本定时器代码移植到触摸画板-3.2寸的例程中,…...

操作教程|MeterSphere UI测试+VNC:简单、快捷地查看UI测试实时执行详情

编者注:本文为CSDN博主hxe116的原创文章。 原文链接为:https://blog.csdn.net/hxe116/article/details/134714960?spm1001.2014.3001.5502 作为一款一站式的开源持续测试平台,MeterSphere涵盖了测试跟踪、接口测试、UI测试和性能测试等功能…...

工具--Git详解

在当今的数字时代,版本控制系统已成为开发人员和团队之间协作的重要工具。其中,Git是最受欢迎的版本控制系统之一。它不仅在软件开发中广泛使用,还被应用于许多其他领域。在这篇博客中,我们将深入了解Git的工作原理、基本命令以及…...

windows server 2022 启用SYN攻击保护

2023.12.28 SYN攻击是什么: SYN攻击是黑客攻击的常用手段,也是最容易被利用的一种攻击手法,属于DDoS攻击的一种。它利用TCP协议缺陷,通过发送大量的半连接请求,耗费CPU和内存资源。 SYN攻击包括大量TCP连接的第一个包&…...

汽车保养软件app开发步骤

“增强您的动力,为您的旅程加油——每一刻都讲述着关爱的故事。构建汽车维护软件app,为您的车辆提供数字化的维修站,从而开启长寿之路。智能驾驶、互联驾驶、自信驾驶。” 疯狂地搜索旧收据并猜测上次换油时间的日子已经一去不复返了。如果您…...

【HarmonyOS】ArkTS语言介绍与组件方式运用

从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是…...

音频播放软件Foobar2000 mac特点介绍

Foobar2000 mac是一款高度可定制的音频播放器,适用于Windows平台。它支持各种音频格式,包括MP3、FLAC、AAC、WMA等,同时也支持各种音频插件和效果器,可以提供更好的音质和用户体验。 Foobar2000 mac软件特点 1. 高度可定制&#…...

Oracle动态性能视图 v$parameter 和 v$parameter2 的区别

v$parameter 的说明见这里: V$PARAMETER displays information about the initialization parameters that are currently in effect for the session. v$parameter2 的说明见这里: V$PARAMETER2 displays information about the initialization paramet…...

ssrf之dict协议和file协议

1.dict协议 dict是什么协议呢? 定义:词典网络协议,在RFC 2009中进行描述。它的目标是超越Webster protocol,并允许客户端在使 用过程中访问更多字典。Dict服务器和客户机使用TCP端口2628。 官方介绍:http://dict.o…...

OpenAI GPT 模型 API 接口新增参数 top_logprobs 和 logprobs

文章目录 一、前言二、主要内容三、总结 🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 在最新的 OpenAI 官方 APIs 文档中,Create chat completion 中新增了 top_logprobs 和 logprobs 这两个关键参数。 官方文档地址&#xff…...

React项目打包流程

一、React项目打包流程 一、React项目打包流程1. 项目打包打包命令:npm run build2. 预览接着命令行会提示执行: 先:npm install -g serve 然后执行此命令:serve -s build二、打包优化 - 配置路由懒加载 二、打包优化 - 配置路…...

04-获取认证的用户身份信息

存储用户信息的方式 获取用户信息的流程 用户提交账号和密码后,DaoAuthenticationProvider调用UserDetailsService接口实现类的loadUserByUsername()方法,该方法可以接收请求参数username的值,然后根据该值查询用户信息,最后将账号,密码,权限封装到UserDetails对象中并返回给…...

二叉树的中序遍历,力扣

目录 题目地址: 题目: 解题方法: 解题分析: 解题思路: 代码实现: 注: 代码实现(递归): 代码实现(迭代): 题目地址&#xf…...

shiro1.10版本后-IniSecurityManagerFactory过期失效

1、问题概述? 今天在研究了shiro的新版本shiro1.13.0版本,发现用了很长时间的IniSecurityManagerFactory工厂失效了。 从下图中可以看出,在新版本中IniSecurityManagerFactory被打上了过期线了。 那么问题来了,新版本如何使用呢…...

阿里后端实习二面

阿里后端实习二面 记录面试题目,希望可以帮助到大家 类加载的流程? 类加载分为三个部分:加载、连接、初始化 加载 类的加载主要的职责为将.class文件的二进制字节流读入内存(JDK1.7及之前为JVM内存,JDK1.8及之后为本地内存)&…...

「Kafka」生产者篇

「Kafka」生产者篇 生产者发送消息流程 在消息发送的过程中,涉及到了 两个线程 ——main 线程和Sender 线程。 在 main 线程中创建了 一个 双端队列 RecordAccumulator。 main线程将消息发送给RecordAccumulator,Sender线程不断从 RecordAccumulator…...

C语言实现RSA算法加解密

使用c语言实现了RSA加解密算法,可以加解密文件和字符串。 rsa算法原理 选择两个大素数p和q;计算n p * q;计算φ(n)(p-1)(q-1);选择与φ(n)互素的整数d;由de1 mod φ(n)计算得到e;公钥是(e, n), 私钥是(d, n);假设明…...

如何设计前后端分离的系统架构?

如何将前端页面和后端Java代码进行集成? 将前端页面和后端Java代码进行集成通常需要使用一些特定的工具和技术。以下是一些常见的方法: 使用RESTful API:REST(Representational State Transfer)是一种基于HTTP协议构…...

【强化学习】SARAS代码实现

前言 SARAS,假设环境状态和动作状态都是离散的。利用动作价值矩阵来进行行为的预测。其主要就是利用时序差分的思想,对动作价值矩阵进行更新。 代码实现 import gymnasium as gym import numpy as npclass sarsa():def __init__(self, states_n, acti…...

P1019 [NOIP2000 提高组] 单词接龙 刷题笔记

P1019 [NOIP2000 提高组] 单词接龙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路来自 大佬 Chardo 的个人中心 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 匹配 &#xff1a; 将 第一个字符串末尾 和第二个字符串第一个开始匹配 如果 j<i这段走完了 flag还没…...

如何实现WinApp的UI自动化测试?

WinApp&#xff08;WindowsAPP&#xff09;是运行在Windows操作系统上的应用程序&#xff0c;通常会提供一个可视的界面&#xff0c;用于和用户交互。例如运行在Windows系统上的Microsoft Office、PyCharm、Visual Studio Code、Chrome&#xff0c;都属于WinApp。常见的WinApp&…...

chrome扩展程序开发之在目标页面运行自己的JS

原文地址&#xff1a;https://qdgithub.com/home/index/article/aid/247.html chrome 插件开发的入门介绍&#xff0c;实现利用 chrome 扩展实现在目标网页运行我们的 js 的功能。关于 chrome 扩展的详细内容&#xff0c;可以通过官网了解。 开发工具很简单&#xff0c;记事本…...

NLP项目之语种识别

目录 1. 代码及解读2. 知识点n-grams仅保留最常见的1000个n-grams。意思是n1000 ? 1. 代码及解读 in_f open(data.csv) lines in_f.readlines() in_f.close() dataset [(line.strip()[:-3], line.strip()[-2:]) for line in lines] print(dataset[:5])[(1 december wereld…...

Linux lpr命令教程:如何使用lpr命令打印文件(附案例详解和注意事项)

Linux lpr命令介绍 lpr命令在Unix-like操作系统中用于提交打印任务。如果在命令行中指定了文件名&#xff0c;那么这些文件将被发送到指定的打印机&#xff08;如果没有指定目的地&#xff0c;则发送到默认目的地&#xff09;。如果命令行中没有列出文件&#xff0c;lpr将从标…...

浅谈C语言inline关键字

对于C开发者来说&#xff0c;inline是个再熟悉不过的关键字&#xff0c;因为默认的成员函数都是inline&#xff0c;也是常规高校教材中宣扬C的“优势”之一。 但是C语言其实也是支持inline关键字的&#xff0c;而且是很早期的gcc就支持了该关键字。在Linux0.12版本内核代码中也…...

Flink1.17实战教程(第六篇:容错机制)

系列文章目录 Flink1.17实战教程&#xff08;第一篇&#xff1a;概念、部署、架构&#xff09; Flink1.17实战教程&#xff08;第二篇&#xff1a;DataStream API&#xff09; Flink1.17实战教程&#xff08;第三篇&#xff1a;时间和窗口&#xff09; Flink1.17实战教程&…...

OpenCV实战 -- 维生素药片的检测记数

文章目录 检测记数原图经过操作开始进行消除粘连性--形态学变换总结实现方法1. 读取图片&#xff1a;2. 形态学处理&#xff1a;3. 二值化&#xff1a;4. 提取轮廓&#xff1a;5. 轮廓筛选和计数&#xff1a; 分水岭算法&#xff1a;逐行解释在基于距离变换的分水岭算法中&…...

【AI】注意力机制与深度学习模型

目录 一、注意力机制 二、了解发展历程 2.1 早期萌芽&#xff1a; 2.2 真正意义的注意力机制&#xff1a; 2.3 2015 年及以后&#xff1a; 2.4 自注意力与 Transformer&#xff1a; 2.5 BERT 与预训练模型&#xff1a; 三、基本框架 1. 打分函数&#xff08;Score Fun…...

HTML5和JS实现新年礼花效果

HTML5和JS实现新年礼花效果 2023兔年再见&#xff0c;2024龙年来临了&#xff01; 祝愿读者朋友们在2024年里&#xff0c;身体健康&#xff0c;心灵愉悦&#xff0c;梦想成真。 下面是用HTML5和JS实现新年礼花效果&#xff1a; 源码如下&#xff1a; <!DOCTYPE html>…...

【owt-server】一些构建项目梳理

【owt-server】清理日志&#xff1a;owt、srs、ffmpeg 【owt】p2p client mfc 工程梳理【m98】webrtc vs2017构建带符号的debug库【OWT】梳理构建的webrtc和owt mfc工程 m79的mfc客户端及owt-client...

Linux shell编程学习笔记38:history命令

目录 0 前言 1 history命令的功能、格式和退出状态1.1 history命令的功能1.2 history命令的格式1.3退出状态2 命令应用实例2.1 history&#xff1a;显示命令历史列表2.2 history -a&#xff1a;将当前会话的命令行历史追加到历史文件~/.bash_history中2.3 history -c&#xf…...

elasticsearch安装教程(超详细)

1.1 创建网络&#xff08;单点部署&#xff09; 因为我们还需要部署 kibana 容器&#xff0c;因此需要让 es 和 kibana 容器互联&#xff0c;所有先创建一个网络&#xff1a; docker network create es-net 1.2.加载镜像 采用的版本为 7.12.1 的 elasticsearch&#xff1b;…...

arkts中@Watch监听的使用

概述 Watch用于监听状态变量的变化&#xff0c;当状态变量变化时&#xff0c;Watch的回调方法将被调用。Watch在ArkUI框架内部判断数值有无更新使用的是严格相等&#xff08;&#xff09;&#xff0c;遵循严格相等规范。当在严格相等为false的情况下&#xff0c;就会触发Watch的…...

【Jmeter】Jmeter基础9-BeanShell介绍

3、BeanShell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法。 3.1、Jmeter中使用的BeanShell 在Jmeter中&#xff0c;除了配置元件&#xff0c;其他类型的元件中都有BeanShell。BeanShell 是一种完全符合Java语法规范的脚本语言,并且又拥…...

详解数组的轮转

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…...

html 表格 笔记

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>第二个页面</title><meta name"language" content"cn"> </head> <body><h2 sytle"width:500px;…...

计算机网络【HTTP 面试题】

HTTP的请求报文结构和响应报文结构 HTTP请求报文主要由请求行、请求头、空行、请求正文&#xff08;Get请求没有请求正文&#xff09;4部分组成。 1、请求行 由三部分组成&#xff0c;分别为&#xff1a;请求方法、URL以及协议版本&#xff0c;之间由空格分隔&#xff1b;请…...

linux基于用户身份对资源访问进行控制的解析及过程

linux中用户分为三类 1.超级用户&#xff08;root&#xff09; 拥有至高无上的权限 2.普通用户 人为创建、权限小&#xff0c;权限受到控制 3.程序用户 运行程序的用户&#xff0c;不是给人使用的&#xff0c;给程序使用的&#xff0c;一般不给登录&#xff01; 组账…...

手动创建idea SpringBoot 项目

步骤一&#xff1a; 步骤二&#xff1a; 选择Spring initializer -> Project SDK 选择自己的JDK版本 ->Next 步骤三&#xff1a; Maven POM ->Next 步骤四&#xff1a; 根据JDK版本选择Spring Boot版本 11版本及以上JDK建议选用3.2版本&#xff0c;JDK为11版本…...

【Go语言入门:Go语言的数据结构】

文章目录 3.Go语言的数据结构&#xff1a;3.1. 指针3.2. struct&#xff08;结构体&#xff09;3.3. Map(映射,哈希&#xff09; 3.Go语言的数据结构&#xff1a; 简介&#xff1a; 在Go语言中&#xff0c;数据结构体可以分为四种类型&#xff1a;基础类型、聚合类型、引用类型…...

QT designer的ui文件转py文件之后,实现pycharm中运行以方便修改逻辑,即添加实时模板框架

为PyCharm中的实时模板&#xff0c;你需要遵循以下步骤&#xff1a; 打开PyCharm的设置: 选择 File > Settings&#xff08;在macOS上是 PyCharm > Preferences&#xff09;。 导航到实时模板: 在设置中找到 Editor > Live Templates。 添加新的模板组 (可选): 为了…...

什么是负载均衡?

负载均衡是指在计算机网络领域中&#xff0c;将客户端请求分配到多台服务器上以实现带宽资源共享、优化资源利用率和提高系统性能的技术。负载均衡可以帮助小云有效解决单个服务器容量不足或性能瓶颈的问题&#xff0c;小云通过平衡流量负载&#xff0c;使得多台服务器能够共同…...

Python和Java的优缺点

Python的优点&#xff1a; 简单易学&#xff1a;Python的语法简洁清晰&#xff0c;易于学习和理解。丰富的库和框架&#xff1a;Python拥有庞大的标准库和活跃的开源社区&#xff0c;可以快速使用各种功能强大的库和框架&#xff0c;比如NumPy、Pandas、Django等。可读性强&am…...

AES - 在tiny-AES-c基础上封装了2个应用函数(加密/解密)

文章目录 AES - 在tiny-AES-c基础上封装了2个应用函数(加密/解密)概述增加2个封装函数的AES库aes.haes.c在官方测试程序上改的测试程序(用来测试这2个封装函数)END AES - 在tiny-AES-c基础上封装了2个应用函数(加密/解密) 概述 在github山有个星数很高的AES的C库 tiny-AES-c …...