Redis核心API速览与实战应用手册

文摘   职场   2024-02-08 11:43   广东  


第 1 章

Redis介绍


Redis是一种key-value键值型的NoSql非关系数据库。键值型,是指Redis中存储的数据都是以key-value键值对的形式存储。value的形式多种多样,可以是字符串、数值、甚至json。非关系型是指没有约束的意思。





Redis通过将数据存储在内存中,提供了极高的读写速度,它读写的延迟时间能降低到微秒级别,能显著的降低响应时间,提高应用程序的性能。但是在使用Redis时也要评估缓存的效益,因为内存资源比较贵,要采用合理的缓存方案,避免滥用缓存导致的系统不稳定和成本增高等问题。


第 2 章

摘要


入门篇-第3章~第5章


第6章-RedisTemplate常用API


第7章-单点登录双token三验证


第8章-查询缓存


第9章-签到功能的实现


第10章-Redis持久化策略


第11章-作者介绍


第 3 章

Redis安装


3.1、Windows


3.1、下载解压


Github下载:

https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100




3.2、启动


在解压文件夹路径栏输入cmd,然后输入redis-server redis.windows.conf就可以启动成功。



3.2、Linux CentOS安装Redis


3.2.1、下载


到Redis官网https://redis.io/download/下载源码安装包,上传到Linux服务器的指定目录。



3.2.2、准备运行环境


// #redis是基于C语言开发,所以编辑redis源码需要安装gcc
yum install -y gcc-c++ autoconf automake
// #centos7 默认的 gcc 默认是4.8.5,版本⼩于 5.3 ⽆法编译,// 需要先安装gcc新版才能编译
// 查看gcc版本号gcc -v
// #升级新版gccyum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
// 配置gcc版本永久生效scl enable devtoolset-9 bash echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
// 解压redis源码安装包tar -zxvf redis-7.2.3.tar.gz
// 重命名mv redis-7.2.3/ redis7
// 进入到redis里面cd redis7
// 在安装包里面编译redismake
// 创建redis文件夹mkdir -p /usr/local/redis
// 编译好redis后,就将安装redismake PREFIX=/usr/local/redis install

3.2.3、设置redis配置文件


vim redis.conf


# 绑定地址,默认为 127.0.0.1,即只接受本地连接  # bind 127.0.0.1
#任何ip可以访问,这里可以指定那些ip可以访问bind 0.0.0.0#守护进程daemonize yes#密码requirepass ************
# 保护模式,默认为 yes,开启后仅允许本地连接 protected-mode yes
# Redis 监听的端口号,默认为 6379port 6379
# TCP 连接队列长度,默认为 511tcp-backlog 511
# 客户端空闲连接超时时间,单位为秒,0 表示不超时断开 timeout 0
# TCP keepalive 参数,用于检测挂掉的客户端连接 tcp-keepalive 300
# 是否在后台运行,默认为 no,即在前台运行 daemonize no
# Redis 进程文件路径 pidfile /var/run/redis/redis.pid
# 日志级别,可选值包括 debug, verbose, notice, warn loglevel notice
#⽇志⽂件路径logfile "/usr/local/redis/log/redis.log"# 是否开启AOF功能,默认是noappendonly yes# AOF文件的名称appendfilename "appendonly.aof"
# 表示每执行一次写命令,立即记录到AOF文件# appendfsync always # 写命令执行完先放入AOF缓冲区,# 然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案# appendfsync everysec # 写命令执行完先放入AOF缓冲区,# 由操作系统决定何时将缓冲区内容写回磁盘# appendfsync no# AOF文件体积最小多大以上才触发重写 # auto-aof-rewrite-min-size 64mb
# RDB 持久化配置(可选)  #持久化⽂件名称dbfilename yxclass.rdb#持久化⽂件存储路径dir /usr/local/redis/data# save <seconds> <changes>#持久化策略, 100秒内有个5个key改动,执⾏快照save 100 5save 5 100

3.2.4、启动redis


cd bin# 启动命令./redis-server ../conf/redis.conf
// 启动后就可以通过远程连接工具进行连接redis了。


第 4 章

Redis基本数据类型


Redis的基本数据类型有五种,分别是String,Hash,List,Set和SortedSet。



4.1、String类型


4.1.1、String类型介绍


Redis的String类型是最基本的数据类型之一,它用于存储字符串值。字符串类型的值最大可以存储512MB的内容

Redis的字符串是动态字符串,类似于Java中的ArrayList,它采用预分配冗余空间的方式来减少内存的频繁分配。当字符串长度小于1MB时,每次扩容会加倍当前空间;当字符串长度大于1MB时,每次只会增加1MB,直到增加至512MB。

4.1.2、Redis的Key结构设计


为了避免不同业务之间的key产生冲突,Redis的key允许有多个单词形成层级结构,多个单词之间用':'隔开,格式如下:

项目名:业务名:类型:id

4.1.3、String类型的Value


如果Value是一个Java对象,例如一个User对象,需要先将对象先序列化为JSON字符串后作为values进行存储:


4.1.4、String类型常用命令


1.设置一个 key-value 对,并设置其 300 秒后过期:


SET mykey "Hello Redis" EX 300



2.获取该 key 的值:


GET mykey




3.修改该 key 的值:


SET mykey "Hello again!"




4.删除该 key:


DEL mykey




5.尝试获取已删除的 key 的值,将返回 nil:


GET mykey

nil是一个对象指针,通常用于表示Objective-C对象的空值,而null是一个宏定义,其值为0,通常用于表示基本类型或C语言中的空指针。对于nil,可以调用方法,不会产生crash或抛出异常,而null则不能调用方法。


4.2、Hash类型


4.2.1、Hash类型介绍


当需要存储对象的值的时候,String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便,而使用Hash类型能解决这个问题。


Redis的Hash类型是一种键值对集合,特别适合用于存储对象。在Hash类型中,每个键都有一个对应的值,其value是一个无序字典,类似于Java中的HashMap结构,以下是对Redis Hash类型的详细介绍:

数据结构:Hash类型是一个String类型的field和value的映射表,可以存储多个键值对。

容量:单个Hash类型可以存储超过4亿个键值对,这使其非常适合存储大量数据。

性能:无论Hash中存储了多少数据,查找某个键的速度都非常快,这使得Hash类型在需要频繁查找的场景下表现出色。



应用场景:

1.用户信息存储:可以将用户的各种信息(如姓名、年龄、邮箱、密码等)存储在一个Hash中,以业务前缀+用户ID作为Hash的key,属性名作为field,属性值作为value。这样,可以非常快速地获取、更新或删除用户的完整信息。

2.对象存储:Hash类型也可以用于存储对象,其中每个field可以看作对象的属性,value可以看作属性的值。这种方式可以方便地对象进行操作,如添加、修改、删除属性等。

3.购物车的实现:可以将每个用户的购物车作为一个独立的Hash,业务前缀加上用户的唯一标识(如用户ID)作为Hash的key,而购物车的具体内容则作为Hash的field和value来存储。例如,我们可以将商品ID作为field,而商品的数量则作为对应的value。这样,每当用户添加或修改购物车中的商品时,我们就可以通过修改Hash中的field和value来实现。

4.2.2、常用命令


1.创建一个Hash并添加一个字段:

HSET user:1000 name "远方的音讯"


2.添加另一个字段到同一个Hash:


HSET user:1000 age 24

3.获取Hash中的一个字段值:


HGET user:1000 name


4.获取Hash中的所有字段和值:


HGETALL user:1000//hget all


5.删除Hash中的一个字段:


HDEL user:1000 age


6.为Hash key设置过期时间(例如,10秒后过期):


EXPIRE user:1000 10//expire


7.等待10秒后,尝试获取已过期的Hash:


HGETALL user:1000//hget all


由于user:1000已经过期,所以将返回一个空结果或者nil。

4.3、List类型


4.3.1、List类型介绍


Redis的List类型是一个双向链表,其中每个元素都是String类型。这个链表支持头插(lpush和lpushx)、头删(lpop)、尾插(rpush和rpushx)和尾删(rpop)操作,而且链表中的元素是可以重复的。由于这些操作都是在链表的头部或尾部进行的,所以它们的时间复杂度都是O(1)

List类型可以用作队列或栈。如果搭配使用rpush和lpop,那么就相当于队列;如果搭配使用rpush和rpop,那么就相当于栈。


4.3.2、List类型常用命令


1.插入:


LPU key value [value ...]:在列表头部插入一个或多个值。如果key不存在,则创建该key并作为列表使用。


LPU mylist "apple" "banana"// 结果:mylist: banana, apple


RPU key value [value ...]:在列表尾部插入一个或多个值。


RPU mylist "cherry"// 结果mylist: banana, apple, cherry




2.删 (移除):


LPOP key:移除并返回列表的头部元素。


LPOP mylist
//结果(返回并移除的元素):"banana"//更新后的列表:mylist: apple, cherry


RPOP key:移除并返回列表的尾部元素。


RPOP mylist
//结果(返回并移除的元素):"cherry"//更新后的列表:mylist: apple




3.改 (修改):


LSET key index value:将列表中指定索引位置的元素值设置为新值。


LSET mylist 0 "orange"
结果:mylist: orange
这里将索引为0的元素(即列表的头部元素)从"apple"修改为了"orange"。




4.查 (获取):


4.1、LRANGE key start stop:获取列表指定范围内的元素。


LRANGE mylist 0 -1
结果返回:"orange"这里获取了整个列表的内容,由于列表只有一个元素,所以只返回了一个元素。


4.2、LINDEX key index:获取列表中指定索引位置的元素。


LINDEX mylist 0
"orange":这里获取了索引为0的元素,即列表的头部元素。




4.3、EXPIRE和PEXPIRE设置有效期:


SET mylist [1 "apple" 2 "banana" 3 "cherry"]  EXPIRE mylist 60


在这个例子中,我们首先使用SET命令创建了一个名为mylist的List,并添加了三个元素。然后,我们使用EXPIRE命令为这个key设置了60秒的过期时间。当60秒过去后,mylist这个key将自动被删除,包括它关联的List数据。


EXPIRE设置的单位是秒,PEXPIRE设置的单位是毫秒值。设置的过期时间是针对整个key的,而不是针对key中的某个元素。这意味着一旦key过期并被删除,与该key关联的所有数据都将丢失。


4.4、Set类型


4.4.1、Set类型介绍


Redis的Set类型是一个无序的、不重复的数据结构,用于存储一组唯一的元素。Set类型在Redis中非常实用,因为它提供了高效的成员查找和去重功能,并且支持交集、并集、差集等功能,常用于处理一些需要存储唯一值的场景

Set类型的底层实际上是一个value为null的hash表,与HashSet类似。他的底层是给予哈希表实现的,因此添加、删除、查找的复杂度都是O(1),这意味着无论数据集中有多少元素,这些操作的时间都是恒定的。


4.4.2、Set类型常用命令


1.增加元素:
SADD:将一个或多个成员添加到集合中。如果集合已经存在该成员,则忽略该操作。


SADD key member [member ...]SADD myset "apple"SADD myset "banana" "cherry"


2.删除元素:
SREM:从集合中移除一个或多个成员。如果成员不存在于集合中,则忽略该操作。


SREM key member [member ...]SREM myset "banana"




3.修改元素:Set不支持直接修改元素,但可以通过删除和添加来实现。



4.查询元素:


SISMEMBER:检查给定成员是否存在于集合中。如果存在返回1,否则返回0。


SISMEMBER key memberSISMEMBER myset "apple"// sismember


SMEMBERS:返回集合中的所有成员。

SMEMBERS keySMEMBERS myset//smembers


SCARD:返回集合中成员的数量。


SCARD keySCARD myset//scard




5.SINTER、SUNION 和 SDIFF 是 Redis 中用于对多个集合执行交集、并集和差集操作的命令。

假设我们有三个集合 setA、setB 和 setC,分别包含以下元素:


SADD setA 1 2 3  SADD setB 2 3 4  SADD setC 3 4 5


5.1、交集


案例:找出这三个集合的交集,即同时属于 setA、setB 和 setC 的元素。

SINTER setA setB setC
//执行上述命令后,将返回交集结果 "3"//这表明只有数字 3 同时存在于 setA、setB 和 setC 中。//sinter




5.2、并集

案例:同样使用上面的 setA、setB 和 setC 集合,现在我们想要找出这三个集合的并集,即属于任何一个集合的所有元素。

SUNION setA setB setC//将返回并集结果:"1" "2" "3" "4" "5"//这表明数字 1、2、3、4 和 5 至少存在于一个集合中。//sunion



5.3、差集

案例:使用 setA 和 setB,我们想要找出属于 setA 但不属于 setB 的元素。

SDIFF setA setB返回差集结果: "1"//sdiff

4.5、SortedSet类型


4.5.1、SortedSet类型介绍


SortedSet是String类型的有序集合,且不允许有重复成员。每个元素都会关联一个double类型的分数。

Redis的ZSet是一种有序的集合数据结构,和Set相比,多了一个分值(score)字段,用于进行排序。ZSet中的每个元素都关联着一个分值,可以根据分值进行查询和统计,也可以使用元素(member)进行查询和增删。比如,可以用ZSet来存储每个用户在网站上的积分值,按分值排序,查询排名前十的用户,或者根据用户id来查询其积分值。ZSet还提供了多个操作方法,例如获取某个元素的分值,获取ZSet的长度、删除元素等等。


4.5.2、SortedSet底层介绍


Redis是通过C写的,ZSet的底层有两种情况,一种是跳表加Hash,另一种是ZipList。

跳表,首先是链表和传统的链表是不一样的,传统的链表一个指针只能指向下一个节点,而ZSet底层的链表可以有多级指针,原本单线链表要找11次,而使用下图的跳表,只需找3次。


1. 跳表是一个双向链表,每个节点都包含score和ele值。
2. 节点按照score值排序,score值一样则按照ele字典排序。
3. 每个节点都可以包含多层指针,层数是1到32之间的随机数。
4. 不同层指针到下一个节点的跨度不同,层级越高,跨度越大。
5. 增删改查效率与红黑树基本一致,实现却更简单。


4.5.3、SortedSet常用命令


1.ZADD 增加命令:


ZADD myzset 1 "one"ZADD myzset 2 "two"ZADD myzset 3 "three"


上述命令将三个成员(one、two、three)及其对应的分数(1、2、3)添加到名为myzset的有序集合中。



2.ZREM 删除命令:


ZREM myzset "two"
这个命令将从myzset有序集合中移除成员"two"。




3.ZINCRBY 命令案例:


ZINCRBY myzset 1 "one"//zincrby


这个命令将myzset中成员"one"的分数增加1。




4.ZRANK 获取升序排名命令:


ZRANK myzset "one"//zrank


这个命令将返回myzset中成员"one"的排名(按分数从小到大排序)。



5.ZREVRANK 获取降序命令:

ZREVRANK myzset "one"//zrevrank


这个命令将返回myzset中成员"one"的排名(按分数从大到小排序)。




6.ZCARD 获取集合所有成员命令:


ZCARD myzset//zcard


这个命令将返回myzset有序集合中的成员数量。




7.ZSCORE 命令案例:


ZSCORE myzset "one"//zscore


这个命令将返回myzset中成员"one"的当前分数。




8.ZRANGE 升序获取所有元素命令:


ZRANGE myzset 0 -1//zrange


这个命令将返回myzset有序集合中的所有成员,按分数从小到大排序。



9.ZREVRANGE 降序获取所有元素命令:


ZREVRANGE myzset 0 -1//zrevrange


这个命令将返回myzset有序集合中的所有成员,按分数从大到小排序。



10.ZCOUNT 获取指定分数之间成员的数量:


ZCOUNT myzset 1 2//zcount


这个命令将返回myzset中分数在1和2之间的成员数量(包括1和2)。



11.ZRANGEBYSCORE :获取指定分数之间的所有成员(升序):


ZRANGEBYSCORE myzset 1 2//zrange by score


这个命令将返回myzset中分数在1和2之间的所有成员(包括1和2)。



12.ZREVRANGEBYSCORE 获取指定分数之间的所有成员


ZREVRANGEBYSCORE myzset 2 1//zrange by score


这个命令将返回myzset中分数在1和2之间的所有成员,按分数从高到低排序(包括1和2)。

第 5 章

SpringDataRedis


Spring Data Redis是Spring框架的一部分,它对Redis的底层开发包(如Redis常用的客户端Jedis和Lettuce)进行了高度封装,使得开发者能够更方便地使用Redis。

具体来说,Spring Data Redis提供了一个名为RedisTemplate的类,该类封装了对Redis的各种操作的API、异常处理以及序列化。


5.2、引入依赖


SpringBoot提供了Spring Data Redis的起步依赖只需在项目中添加相应的 Redis 依赖,就可以在项目使用RedisTemplate这个类对Redis进行操作。无需深入了解底层细节,简化了开发流程,让开发者能够专注于业务逻辑的实现


<!--redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
<!--common-pool用于创建和管理对象的池, <!--以减少创建和销毁对象时的开销。 <!--通过使用对象池,可以重用已经创建的对象, <!--而不是每次需要时都创建新的对象。 <!--这可以显著提高应用程序的性能和响应时间。--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
<!--Jackson依赖--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>


5.3、配置Redis连接


spring:  redis:    host: yxclass.net    port: 6379    password: **********    // Lettuce连接池    lettuce:      pool:      // 连接池的最大活动连接数。        max-active: 8        max-idle: 8        min-idle: 0        max-wait: 100ms

max-wait:当连接池中没有可用连接时,新的连接请求将会等待一个连接被释放的最大时间。超过这个时间后,如果没有可用的连接,请求将会失败。

5.4、自定义序列化


如下图所示,使用JDK默认的序列化方式:可读性差,内存占用较大



我们通过可以自定义RedisTemplate的序列化方式解决可读性差,内存占用较大这个问题,配置代码如下:


/** * @description: 配置redis的序列化方式。提高可读性和传输性。 * @author wcj18 * @date 2024-02-04 19:07 * @retrun */@Configurationpublic class RedisConfig {    @Bean    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){        // 创建RedisTemplate对象        RedisTemplate<String, Object> template = new RedisTemplate<>();        // 设置连接工厂        template.setConnectionFactory(connectionFactory);        // 创建JSON序列化工具        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();        // 设置Key的序列化        template.setKeySerializer(RedisSerializer.string());        template.setHashKeySerializer(RedisSerializer.string());        // 设置Value的序列化        template.setValueSerializer(jsonRedisSerializer);        template.setHashValueSerializer(jsonRedisSerializer);        // 返回        return template;    }}


使用JSON序列化来代替默认的JDK序列化方式,就能解决乱码显示情况,以及占用内存更小。



第 6 章

RedisTemplate常用API



6.1、opsForValue


opsForValue操作String类型的数据操作字符串类型的数据,可以使用RedisTemplate的子类:StringRedisTemplate,它的key和value的序列化方式默认就是String方式,这样可以节省内存空间。当需要存储Java对象时,手动完成对象的序列化和反序列化即可。



5.5.1、手动完成对象的序列化和反序列化


手动序列化:将Java对象转为json字符串。



反序列化:将json字符串转为Java对象。



5.5.2、说说你对序列化和反序列化的理解


首先,我认为,之所以需要序列化,核心目的是为了解决网络通信之间的对象传输的问题。就是把当前JVM进程里面的一个对象,跨网络传输到另外一个JVM进程里面。

序列化,就是把内存里面的对象转化为字节流,以便用来实现存储或者传输。

反序列化,就是根据从文件或者网络上获取到的对象的字节流里面保存的对象描述信息和状态重新构建一个新的对象。

其次呢,序列化的前提是保证通信双方对于对象的可识别性,所以很多时候,我们会把对象先转化为通用的解析格式,比如json、xml等。然后再把他们转化为数据流进行网络传输,从而实现跨平台和跨语言的可识别性。

在项目中引入阿里fastjson的依赖,就可以调用JSON.toJSONString(对象名)方法将对象转换为json字符串,调用JSON.parseObject(json,类名.class)将json字符串反序化为Java对象。



5.5.3、StringRedisTemplate


使用StringRedisTemplate存储字符串时,可以直接作为value进行存储,存储对象前要先设置自定义序列化,而且实体类要实现Serializable接口



serialVersionUID用于在反序列化过程中验证序列化和反序列化对象的版本兼容性。这是为了防止在不同版本的类之间进行反序列化时发生错误。





1.存储对象和设置过期时间:


存储对象:set(key,value)。

设置时效:expire(key,时长,单位)。



方法执行结果:





2.更新对象信息,用原来的key重新赋值就是把原来的替换掉。









3.删除对象信息:stringRedisTemplate.delete(key)




4.获取对象信息:opsForValue.get(key)

远方的音讯
梧桐长成凤凰至,人伴贤良品行高!
 最新文章