Redis--学习记录

Redis

一、概念

可参考官网
Redis中文网
官网:
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库高速缓存消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。

二、安装Redis

0、Redis环境安装

Redis是C语言开发,安装Redis需要先将Redis的源码进行编译,编译依赖gcc环境。因此需要安装gcc

安装命令

yum -y install gcc-c++

如图:
在这里插入图片描述

1、Windows安装

(1)下载压缩包

下载地址
在这里插入图片描述

(2)解压

在这里插入图片描述

(3)启动Redis测试

双击redis-server.exe或cmd命令输入redis-server.exe启动

在这里插入图片描述
启动redis-cli输入ping看是否能ping通
在这里插入图片描述
显示pong证明安装成功了

2、Linux安装

(1)下载压缩包并传到Linux服务器上
使用工具软件来连接我这里使用的是finalshell

Redis官网下载地址
在这里插入图片描述
传到指定的文件夹里面去
在这里插入图片描述

(2)解压到指定目录
解压命令
tar -zxvf redis-7.0.8.tar.gz

在这里插入图片描述

(3)编译安装
进入解压出来的目录执行 make 命令(依次执行下面的命令)
cd /home/biji/redis-7.0.8/ #进入Redis解压后的文件目录
make #编译
# PREFIX一定要大写,否则失效。亲测
make PREFIX=/usr/local/redis install#安装,如果不指定安装位置默认会 在/usr/local/bin下面
(4)修改、配置redis.conf文件

在解压的redis文件中修改redis.conf的内容然后复制一份到上面make的路径下,目的是,留一份初始版本的配置文件,以防改坏了配置(配置文件两千多行),需要重新安装,麻烦

daemonize yes 意思是开启进程守护,理解为后台运行。
在这里插入图片描述

cp redis.conf /usrl/local/redis/bin # 把redis.conf复制到该目录下
(5)启动Redis测试
./redis-server redis.conf #启动redis
./redis-cli #启动redis-li客户端

在这里插入图片描述
ping能通过
安装成功

三、Redis五大基本数据类型

0、key相关的一些方法

keys * #获得查看key
flushdb # 清空当前选择的数据库的所有数据
flushall # 清空素有数据库的数据
expire key seconds # 设置某个key的过期时间
ttl key # 查看某个key的剩余时间
DEL key # 该命令用于在 key 存在是删除 key。
renamenx key newkey # 仅当 newkey 不存在时,将 key 改名为 newkey 。
127.0.0.1:6379> keys *
1) "list"
127.0.0.1:6379> rename list newlist
OK
127.0.0.1:6379> keys *
1) "newlist"
127.0.0.1:6379> renamenx newlist list
(integer) 1
127.0.0.1:6379> keys *
1) "list"

1、字符串(String)类型

Redis 字符串数据类型的相关命令用于管理 redis 字符串值,基本语法如下:
(1)set、get方法
就是正常的存和取的方法
127.0.0.1:6379> set name lkiku
OK
127.0.0.1:6379> get name
"lkiku"
127.0.0.1:6379> get name
"lkiku"
127.0.0.1:6379> 
(2)setnx方法(当key不存在时才写入)、setex方法(存入的同时设置过期时间)
setnx和set方法的区别是set方法不管是否存在都会写入,有的话会覆盖之前的值
setex方法是会加上过期时间的
127.0.0.1:6379> get name
"lkiku"
127.0.0.1:6379> set name newname
OK
127.0.0.1:6379> get name
"newname"
127.0.0.1:6379> setnx name wlh
(integer) 0
127.0.0.1:6379> get name
"newname"
127.0.0.1:6379> set id 101
OK
127.0.0.1:6379> ttl id # 查看剩余时间
(integer) -1
127.0.0.1:6379> del id
(integer) 1
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> setex id 60 102 # setex key 秒数 value
OK
127.0.0.1:6379> get id
"102"
127.0.0.1:6379> ttl id
(integer) 54
127.0.0.1:6379> 

(3)mset、mget方法
用于批量操作,具有类似MySQL的事务性,整个set操作同成功同失败
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 aaaaa
(error) ERR wrong number of arguments for 'mset' command #在存入v3之前都是正常的,最后出现了问题,但是之前的数据并没有存入同成功同失败
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> 
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"
127.0.0.1:6379> 
(4)incr、decr、incrby、decryby方法
整数的加减
127.0.0.1:6379> set i 0
OK
127.0.0.1:6379> incr i # 自增1 相当于 i++
(integer) 1
127.0.0.1:6379> get i
"1"
127.0.0.1:6379> incrby i 10 # 指定增加的值  相当于i=i+10
(integer) 11
127.0.0.1:6379> get i 
"11"
127.0.0.1:6379> decr i # 自减 相当于i--
(integer) 10
127.0.0.1:6379> get i
"10"
127.0.0.1:6379> decrby i 5 # 指定减少的值 相当于 i=i-5
(integer) 5
127.0.0.1:6379> get i
"5"
127.0.0.1:6379> 
(5)字符串的相关操作
append 追加
strlen 获得字符串的长度
setrange  从指定的下标开始覆盖
127.0.0.1:6379> set name redis
OK
127.0.0.1:6379> strlen name
(integer) 5
127.0.0.1:6379> append name hello #追加
(integer) 10
127.0.0.1:6379> get name
"redishello"
127.0.0.1:6379> setrange name 4 " hello!" # 覆盖,从指定下标开始覆盖,依次覆盖
(integer) 11
127.0.0.1:6379> get name
"redi hello!"

2、哈希(Hash)类型

哈希:可以理解为key:{k1:v1,k2:v2...}
如:user : {id:1,name:kiku,age:18}
Hmset 命令 # 同时将多个 field-value (域-值)对设置到哈希表 key 中。
Hmget 命令	# 获取所有给定字段的值
Hset 命令	# 将哈希表 key 中的字段 field 的值设为 value 。
Hgetall 命令	# 获取在哈希表中指定 key 的所有字段和值
Hget 命令	# 获取存储在哈希表中指定字段的值/td>
Hexists 命令	# 查看哈希表 key 中,指定的字段是否存在。 
Hincrby 命令	# 为哈希表 key 中的指定字段的整数值加上增量 increment 。
Hlen 命令	# 获取哈希表中字段的数量
Hdel 命令	# 删除一个或多个哈希表字段
Hvals 命令	# 获取哈希表中所有值
Hincrbyfloat 命令	# 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
Hkeys 命令	# 获取所有哈希表中的字段
Hsetnx 命令	# 只有在字段 field 不存在时,设置哈希表字段的值。
127.0.0.1:6379> hset map k1 v1 k2 v2 name wlh age 18 phone 10086
(integer) 5
127.0.0.1:6379> hgetall map
 1) "k1"
 2) "v1"
 3) "k2"
 4) "v2"
 5) "name"
 6) "wlh"
 7) "age"
 8) "18"
 9) "phone"
10) "10086"
127.0.0.1:6379> hget map name
"wlh"
127.0.0.1:6379> hmset user name qq age 20 id 1 # 批量操作
OK
127.0.0.1:6379> hmget map name age id
1) "wlh"
2) "18"
3) (nil)
127.0.0.1:6379> hmget user  name age id # 批量操作
1) "qq"
2) "20"
3) "1"
127.0.0.1:6379> hexists map id
(integer) 0
127.0.0.1:6379> hexists map name #判断是哈希中是否存在某个值
(integer) 1
127.0.0.1:6379> hlen map # 获取hash的长度
(integer) 5
127.0.0.1:6379> hlen user
(integer) 3
127.0.0.1:6379> hkeys map # 获取key列表
1) "k1"
2) "k2"
3) "name"
4) "age"
5) "phone"
127.0.0.1:6379> hdel map k1 k2 # 删除哈希中的key-value
(integer) 2
127.0.0.1:6379> hkeys map
1) "name"
2) "age"
3) "phone"

3、列表(List) 类型

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

一个列表最多可以包含 2的32次方 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。

127.0.0.1:6379> lpush list 1 2 3
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 获取列表指定范围内的元素 0 -1表示全部
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> rpush list 3 2 1
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "3"
5) "2"
6) "1"
127.0.0.1:6379> rpop list 3 # 从下面依次弹出元素 3位弹出的个数
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lpop list 1 # 从上面依次弹出元素 1位弹出的个数
1) "3"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
127.0.0.1:6379> lpush list 10 9
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "9"
2) "10"
3) "2"
4) "1"
127.0.0.1:6379> lindex list 1 # 从上往下算下标,从0开始,获取对应下标的数据
"10"
127.0.0.1:6379> llen list # 获取list的长度
(integer) 4
127.0.0.1:6379> lrem list 1 10 # lrem key count element 删除指定的list中多少个某一个元素
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "9"
2) "2"
3) "1"
127.0.0.1:6379> ltrim list 0 1 # 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
OK
127.0.0.1:6379> lrange list 0 -1
1) "9"
2) "2"

127.0.0.1:6379> linsert list before 9 10 # linsert key BEFORE|AFTER pivot element 在指定的下标前或后插入元素
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "10"
2) "9"
3) "2"
127.0.0.1:6379> linsert list after 2 1 0
(error) ERR wrong number of arguments for 'linsert' command # 插入单个元素
127.0.0.1:6379> linsert list after 2 1
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "10"
2) "9"
3) "2"
4) "1"
127.0.0.1:6379> lpush list2 a b c
(integer) 3
127.0.0.1:6379> keys *
1) "list2"
2) "list"
127.0.0.1:6379> lrange list 0 -1
1) "10"
2) "9"
3) "2"
4) "1"
127.0.0.1:6379> lrange list1 0 -1
(empty array)
127.0.0.1:6379> lrange list2 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> rpoplpush list list1 # rpoplpush 弹出并插入 rpoplpush 源list 目标list
"1"
127.0.0.1:6379> lrange list1 0 -1
1) "1"
127.0.0.1:6379> lrange list2 0 -1
1) "c"
2) "b"
3) "a"

通过对应的一些方法可以实现一些数据结构,如栈和队列等
在这里插入图片描述

4、集合(Set) 类型

Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

sadd key member [member ...] # 向集合中添加元素
Sunion # 返回所有给定集合的并集
Scard # 获取集合的成员数
Srandmember # 返回集合中一个或多个随机数
Smembers # 返回集合中的所有成员
Sinter # 返回给定所有集合的交集
Srem # 移除集合中一个或多个成员
Smove # 将 member 元素从 source 集合移动到 destination 集合
Sadd # 向集合添加一个或多个成员
Sismember # 判断 member 元素是否是集合 key 的成员
RSdiffstore # 返回给定所有集合的差集并存储在 destination 中
RSdiff # 返回给定所有集合的差集
Sscan # 迭代集合中的元素
Sinterstore # 返回给定所有集合的交集并存储在 destination 中
Sunionstore # 所有给定集合的并集存储在 destination 集合中
Spop # 移除并返回集合中的一个随机元素

跑一部分感觉用的多的命令

127.0.0.1:6379> sadd set 1 2 3 4 5 6 # 向set中添加元素
(integer) 6
127.0.0.1:6379> scard set
(integer) 6
127.0.0.1:6379> srandmember set 3
1) "3"
2) "5"
3) "1"
127.0.0.1:6379> sadd set2 1 2 3 a b c
(integer) 6
127.0.0.1:6379> sunion set set2 # 集合的并集(相同的会去重,集合的特性)
1) "4"
2) "3"
3) "6"
4) "5"
5) "b"
6) "2"
7) "a"
8) "1"
9) "c"
127.0.0.1:6379> smembers set #smembers key 获取指定set里的全部元素
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379> smembers set2
1) "3"
2) "b"
3) "2"
4) "1"
5) "a"
6) "c"
127.0.0.1:6379> sdiff set set2 # 集合的差集sdiff key [key ...] 第一个和后面的集合之间的差集 set - set2
1) "4"
2) "5"
3) "6"
127.0.0.1:6379> sdiff set2 set # set2 - set
1) "b"
2) "a"
3) "c"
127.0.0.1:6379> sinter set set2 # 交集
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> sismember set 2 # sismember key element 判断集合中是否存在该元素,0不存在,1存在
(integer) 1
127.0.0.1:6379> sismember set 10
(integer) 0
127.0.0.1:6379> smove set set2 1 # 把第一个集合中的元素移到第二个集合中
(integer) 1
127.0.0.1:6379> smembers set2
1) "3"
2) "b"
3) "2"
4) "1"
5) "a"
6) "c"
127.0.0.1:6379> smembers set
1) "2"
2) "3"
3) "4"
4) "5"
5) "6"
127.0.0.1:6379> spop set 1 # 移除并返回集合中的一个随机元素(可以移除多个)
1) "5"
127.0.0.1:6379> spop set 3
1) "2"
2) "3"
3) "6"
127.0.0.1:6379> smembers set
1) "4"

5、有序集合(sorted set)类型

Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

命令地址:有序集合命令
更多Redis相关命令

三、事务

主要命令
exec 执行事务内的所有命令
multi 开启事务
discard 放弃事务
watch 监听事务中的值,当里面的值发生改变时事务将被打断
unwatch 取消监听

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> sadd myset 1 2 3 # 添加set集合的命令进入事务队列
QUEUED
127.0.0.1:6379(TX)> sadd youset a bc # 添加set集合的命令进入事务队列
QUEUED
127.0.0.1:6379(TX)> exec # 提交事务,执行队列中的所有命令
1) (integer) 3
2) (integer) 2
127.0.0.1:6379> smembers myset
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> smembers youset
1) "bc"
2) "a"

开两个redis-cli连接redis服务,一个去监听某一个key,另一个来实现在监听的过程中改变这个key,以此来实现乐观锁

在这里插入图片描述

在这里插入图片描述

cli1 – 监听i

127.0.0.1:6379> set i 0
OK
127.0.0.1:6379> watch i
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> append i 11 # 先不执行
QUEUED

cli2 – 修改i的值

127.0.0.1:6379> keys *
1) "myset"
2) "youset"
127.0.0.1:6379> keys *
1) "myset"
2) "i"
3) "youset"
127.0.0.1:6379> set i 10
OK

回到cli1提交事务

127.0.0.1:6379(TX)> exec # 失败
(nil)
127.0.0.1:6379> get i # 没发生改变
"10"

四、发布订阅

命令介绍:
Unsubscribe 命令 指退订给定的频道。
Subscribe 命令 订阅给定的一个或多个频道的信息。
Pubsub 命令 查看订阅与发布系统状态。
Punsubscribe 命令 退订所有给定模式的频道。
Publish 命令 将信息发送到指定的频道。
Psubscribe 命令 订阅一个或多个符合给定模式的频道。

(1)首先在 cli2中创建了订阅频道名为 redisserver

127.0.0.1:6379> subscribe redisserver

在这里插入图片描述

(2)在cli1中向redisserver的频道发送消息

127.0.0.1:6379> publish redisserver hello,redis
(integer) 1

在这里插入图片描述
可以在cli2 里面看到消息
在这里插入图片描述

(3)其他命令

127.0.0.1:6379> UNSUBSCRIBE rediserver # 退订
1) "unsubscribe"
2) "rediserver"
3) (integer) 0
127.0.0.1:6379> PUBSUB CHANNELS # 返回订阅的频道
1) "redisserver"
127.0.0.1:6379> PUBSUB CHANNELS # 在开一个窗口订阅一个新的
1) "pingdao2"
2) "redisserver"
127.0.0.1:6379> PUBSUB CHANNELS *re* # PUBSUB CHANNELS [pattern] 匹配
1) "redisserver"

在这里插入图片描述

五、配置文件redis.conf常用模块详解

(0)开头

可以指定单位,通常是以 k,gb,m的形式出现,并且单位不区分大小写。
在这里插入图片描述

(1)INCLUDES 包含模块

用于引入其他配置文件
在这里插入图片描述

(2)NETWORK 网络模块

bind 默认情况bind=127.0.0.1只能接受本机的访问请求
在这里插入图片描述
如果开启了protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应
将本机访问保护模式设置no,redis在服务器上的时候就需要设置为no

在这里插入图片描述
端口号,默认 6379
在这里插入图片描述
timeout:表示一个空闲的客户端维持多少秒会关闭,0表示关闭该功能。即永不关闭。
在这里插入图片描述
tcp-keepalive :单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞,官方给出的建议值是300s,如果设置为0,则不会周期性的检测。
在这里插入图片描述

(3)GENERAL 通用模块

进程守护,设置daemonize yes代表开启进程守护,默认为no
在这里插入图片描述
设置当前服务启动时把pid进程信息存到对应的文件中
在这里插入图片描述
设置日志级别
在这里插入图片描述
logfile:日志的输入位置,默认是在控制台里面
databases:数据库的个数,默认是16个
在这里插入图片描述

(4)SNAPSHOTTING 快照模块

说明:由于redis是缓存在内存当中的,内存数据易挥发,所以需要一些持久化操作来进行定时存储,保证不会丢失数据,有两种方式分别为rdb和aof,aof在下面也有配置
rdb中存的是数据二进制的形式,aof中存储的是命令
快照:数据持久化

3600 秒(一小时)后,如果至少执行了 1 次更改就执行持久化操作
300 秒(5 分钟)后(如果至少执行了 100 次更改)就执行持久化操作
60 秒后,如果至少执行了 10000 次更改就执行持久化操作
在这里插入图片描述
1、stop-writes-on-bgsave-error :默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。 这将使用户意识到(以一种艰难的方式)数据没有正确持久化在磁盘上,否则很可能没有人会注意到并且有些灾难将会发生。如果后台保存过程将再次开始工作,Redis 将自动允许再次写入。但是,如果您已设置对 Redis 服务器的正确监控 和持久性,您可能希望禁用此功能,以便即使磁盘、权限等问题,Redis 也能继续照常工作。

2、rdbcompression ;默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。

3、rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。可选值为:yes、no、clients
在这里插入图片描述
在这里插入图片描述
dbfilename :设置快照的文件名,默认是 dump.rdb
dir:设置快照文件的存放路径,这个配置项一定是个目录,默认为 ‘./’
在这里插入图片描述

(5)REPLICATION 主从复制模块

因为redis不能保存一定不会出现问题,但已出现问题就可能使这个缓存不能使用了,就会导致很多问题,例如:缓存宕机后,请求数据都会去mysql执行,导致mysql有可能承载不住,再然后如果有写入的操作,单机redis凉了,且未持久化的话数据也会丢失。
在这里插入图片描述
replicaof masterid masterport 一般在从机的配置里面配置主机的信息,配置主机的ip、端口
masterautho:加入注解设置了密码,这里可以配置主机的密码用于连接上主机

在这里插入图片描述

replica-serve-stale-data:默认值为yes
当一个 replica与 master 失去联系,或者复制正在进行的时候,replica可能会有两种表现:
1) 如果为 yes ,replica仍然会应答客户端请求,但返回的数据可能是过时的,如果这是第一次同步,数据可能是空的
2) 如果为 no ,在你执行除了 INFO, REPLICAOF, AUTH, SHUTDOWN, REPLCONF, ROLE, CONFIG, SUBSCRIBE,UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST,HOST and LATENCY之外的其他命令时,replica都将返回一个 “MASTERDOWN Link with MASTER is down” 的错误
在这里插入图片描述
replica-read-only yes:配置Redis的replica实例是否接受写操作,即replica是否为只读Redis。默认值为yes。也就是默认只读不写
在这里插入图片描述
repl-diskless-sync yes :是否开启无盘同步。设置主从复制的方式:磁盘或套接字。
磁盘方式:Redis 主节点创建一个将 RDB 文件写入磁盘的新进程。稍后,父进程以增量方式将文件传输到副本。
套接字方式:Redis 主节点创建一个新进程,该进程直接将 RDB 文件写入副本套接字,而无需接触磁盘。
使用磁盘支持的复制,在生成 RDB 文件时,可以在当前子级时立即排队并随 RDB 文件一起提供更多副本生成 RDB 文件即可完成其工作。
改用无盘复制传输开始后,到达的新副本将排队,新的副本 传输将在当前传输终止时开始。使用无盘复制时,主服务器等待可配置量的开始传输之前的时间(以秒为单位),希望多个 副本将到达,并且可以并行传输。使用慢速磁盘和快速(大带宽)网络,无盘复制效果更好。
在这里插入图片描述
repl-diskless-sync-delay 5 设置无盘同步延迟秒数默认为5 ,0为关闭延迟,直接同步
在这里插入图片描述
repl-diskless-sync-max-replicas 0 默认值为0
启用无盘复制但有延迟时,如果已连接的最大副本数,则可以在达到最大延迟之前让复制开始。默认值为 0 表示最大值未定义,Redis 将等待完全延迟。
在这里插入图片描述
repl-diskless-load disabled 禁用无盘加载,默认是禁用了的
下面是可选值和其描述:

禁用” - 不使用无盘加载(首先将 rdb 文件存储到磁盘)
on-empty-db” - 仅在完全安全时才使用无盘加载。
swapdb” 将当前数据库内容保存在 RAM 中,同时直接从套接字解析数据。此模式下的副本可以在复制过程中继续提供当前数据集,除非它们无法将 master 识别为具有来自相同复制历史记录的数据集。请注意,这需要足够的内存,如果没有它,您将面临 OOM 死亡的风险。

在这里插入图片描述
replica-priority 设置副本优先级,默认值为100
在这里插入图片描述

(6)SECURITY 安全模块

requirepass xxxx:设置密码
在这里插入图片描述

(7)CLIENTS 客户端配置

maxclients 1000:设置客户端最大连接数量,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件。 描述符数-32(redis server自身会使用一些),如果设置 maxclients为0 。表示不作限制。
在这里插入图片描述

(8) MEMORY MANAGEMENT 内存管理

redis是基于内存的的key-value数据库,由于系统内存大小有限,我们在使用redis时可以通过配置使用redis最大的内存大小。
然后需要解决的问题就是当存的数据达到内存的最大值的时候要么就不能继续存入数据,要么淘汰一部分数据来置换数据内存

maxmemory < bytes > 用于设置redis内存大小
在这里插入图片描述
maxmemory-policy noeviction 设置当内存使用达到maxmemory设置的最大值时,redis使用的内存策略。
在这里插入图片描述
有以下几种可以选择:

Redis内存策略:默认采用的是noeviction策略
在这里插入图片描述
从上往下是:

1、volatile-lru策略:从设置了过期时间的key中使用LRU算法进行淘汰
2、allkes-lru策略:从所有的key中使用LRU算法进行淘汰
3、volatile-lfu策略:从设置了过期时间的key中使用LFU算法进行淘汰
4、allkeys-lfu策略:从所有的key中使用LRU算法进行淘汰
5、volatile-random策略:从设置了过期时间的的key中使用随机淘汰策略
6、allkeys-random策略:从所有的key中使用随机淘汰策略
7、volatile-ttl策略:删除过期时间最近的key
8、noeviction策略:当内存满了之后,再次写入时不淘汰数据,直接报错,对查询操作不影响

LRU(Least Recently Used)算法: 淘汰最近没被用到的key-value数据,根据最近一次访问的时间来淘汰。核心思想是:如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。
LFU(Least Frequently Used)算法: 根据key的最近被访问的频率进行淘汰,很少被访问的优先被淘汰,被访问的多的则被留下来。

(9)APPEND ONLY MODE 仅追加模式配置

配置Redis持久化的方式之一:aof方式

appendonly no设置是否开启aof持久化
Redis中默认只开启的rdb模式,在绝大部分都够用了,但是rdb的持久化需要在有更改的时候才能去执行持久化,这就会导致最近几分钟的数据可能会丢失
在这里插入图片描述
appendfilename “appendonly.aof” 设置持久化文件的名称

appenddirname “appendonlydir” 设置持久化文件的目录的名称
在这里插入图片描述
appendfsync everysec:设置追加的方式,
分为always:每次变更都写,
everysec:每秒持久化写入一次,
no:不写入

在这里插入图片描述
no-appendfsync-on-rewrite: 在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。 设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no 。

auto-aof-rewrite-percentage: 默认值为100。aof自动重写配置,当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程。

auto-aof-rewrite-min-size:64mb 设置允许重写的最小aof文件大小,避免了达到约定百分比但文件大小仍然很小的情况还要重写。
在这里插入图片描述
aof-load-truncated 作用:指定当发生AOF文件末尾截断时,加载文件还是报错退出,默认为yes

yes :末尾被截断的 AOF 文件将会被加载,并打印日志通知用户。
no :服务器将报错并拒绝启动。

在这里插入图片描述

(10) REDIS CLUSTER Redis集群配置

cluster-enabled yes 开启Redis集群

在这里插入图片描述cluster-config-file nodes-6379.conf 每个群集节点都有一个群集配置文件。在这里可以进行设置
集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息。 这个文件并不需要手动配置,这个配置文件有Redis生成并更新,每个Redis集群节点需要一个单独的配置文件。请确保与实例运行的系统中配置文件名称不冲突。默认配置为nodes-6379.conf。

在这里插入图片描述
cluster-node-timeout 15000 设置节点多少时间无法访问将其变为故障状态
在这里插入图片描述
cluster-slave-validity-factor : 可以配置值为10。在进行故障转移的时候,全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间了, 导致数据过于陈旧,这样的slave不应该被提升为master。该参数就是用来判断slave节点与master断线的时间是否过长。判断方法是:比较slave断开连接的时间和(node-timeout * slave-validity-factor) + repl-ping-slave-period 如果节点超时时间为三十秒, 并且slave-validity-factor为10,假设默认的repl-ping-slave-period是10秒,即如果超过310秒slave将不会尝试进行故障转移

在这里插入图片描述

cluster-migration-barrier 1 默认值为 1(仅当其主节点保留至少一个副本时,复制副本才会迁移)。要禁用迁移,只需将其设置为非常大的值或将群集允许副本迁移设置为“否”。可以设置值 0,但仅对调试有用,在生产中很危险。

在这里插入图片描述

cluster-require-full-coverage yes: 默认的Redis群集节点在检测到查询时停止接受查询至少有一个哈希槽未覆盖(没有可用节点为其提供服务)。
如果集群部分关闭(例如,一系列哈希槽不再覆盖)所有集群最终都变得不可用。一旦再次覆盖所有插槽,它就会自动返回可用状态。然而,有时您需要正在工作的集群的子集,继续接受对仍然存在的密钥空间部分的查询盖满。要做到这一点,只需设置集群需要完全覆盖选择否在这里插入图片描述

六、实现主从复制,搭建master-slave

目标:一主二从:一个master,两个slave

0、复制修改三份redis.conf文件,用于在一台电脑上启动三个redis服务

6379为master,6380、6381为从机

需要修改的信息为redis服务相关的端口、pid文件、持久化文件、log文件等
(1)进入redis的conf目录复制多份配置
[root@localhost conf]# cp redis.conf redis79.conf
[root@localhost conf]# ll
总用量 216
-rw-r--r--. 1 root root 106545 2月  23 18:36 redis79.conf
-rw-r--r--. 1 root root 106545 2月  23 05:42 redis.conf
[root@localhost conf]# cp redis.conf redis80.conf # 复制conf文件
[root@localhost conf]# cp redis.conf redis81.conf
[root@localhost conf]# ll
总用量 432
-rw-r--r--. 1 root root 106545 2月  23 18:36 redis79.conf
-rw-r--r--. 1 root root 106545 2月  23 18:36 redis80.conf
-rw-r--r--. 1 root root 106545 2月  23 18:36 redis81.conf
-rw-r--r--. 1 root root 106545 2月  23 05:42 redis.conf
(2)修改每一个服务对应的信息

默认的6379我们动不动都可以,我嫌难得改,就直接修改80和81 的即可
6380服务端口redis.conf

vim redis80.conf # 编辑文件

修改端口
在这里插入图片描述
打开守护进程
在这里插入图片描述
修改pid文件的存放名称,和其他放在一个目录下就行
在这里插入图片描述
修改日志文件的名称
在这里插入图片描述
修改rdb持久化的文件名称,和其他redis服务放在同一个目录下
在这里插入图片描述
如果你设置了aof的持久化,也需要修好aof持久化文件的位置或名称,对于6381的redis服务也通过像上述一样的修改
6381端口redis.conf
请添加图片描述
在这里插入图片描述

请添加图片描述
在这里插入图片描述

(3)依次启动server和client
./redis-server redis.conf # 指定配置启动
./redis-cli -p port # 如./redis-cli -p 6379 连接6379的redis服务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查看是否都启动成功

ps -ef|grep redis 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
说明配置完成、启动成功

1、命令行的形式设置主从复制模式

不在redis.conf中的主从模块设置主从信息的时候默认启动的redis都是master
可以通过命令行的形式改为从机
127.0.0.1:6379> info replication # 查看主从复制的信息
# Replication
role:master # 为master
connected_slaves:0 # 连接的从机个数
master_failover_state:no-failover
master_replid:588905b424edb929544b9f588ad3d5044f13b8bf
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:49d05359f7c71dde8612e4326d86af9a2a541d88
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:7bb585e41f0a9e5b9ee3ce11464866ffcecd5848
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

上述都看出全是master,并不是设置了主从。
设置主从的方式有命令和修改配置两种,这里看命令的形式,下面看修改配置文件的形式

slaveof ip port # 设置主机的ip、port

在6380的redis服务中执行 slaveof localhost 6379设置主机信息。
在这里插入图片描述
可以再次使用info replication来看主从信息
在6380端口的服务看如下信息
在这里插入图片描述
在6379端口的服务看如下信息
在这里插入图片描述
同理我们可以在6381端口设置主机信息,去连接主机变为主从
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用主从复制:
一般默认的情况下都是主机(master)能读写,而从机(slave)只能读。
测试:
(1)在主机6379端口的服务存入值
在这里插入图片描述
(2)在从机上获取值
在这里插入图片描述
在这里插入图片描述
都能获取到master存进去的值,若使用从机(slave)去存值则报错
(error) READONLY You can’t write against a read only replica.在这里插入图片描述

2、修改配置文件的形式设置主从复制模式

在上面的配置文件详解里面有REPLICATION 主从复制模块的配置,所以我们可以在REPLICATION 主从复制模块里面配置即可,直接启动就是一个从机(slave)去连接主机(master)

(1)修改配置文件

修改6380的redis.conf文件,配置master

在这里插入图片描述
修改6381的redis.conf文件,配置master

在这里插入图片描述

(2)启动Redis服务连接测试

依次启动master-slave

6379:
在这里插入图片描述
6380:
在这里插入图片描述
6381:
在这里插入图片描述
实现master写、slave读测试:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试通过,说明配置成功

3、扩展(master宕机问题)

1、当master宕机了之后会怎么样?
2、slave还能不能获得值?
3、还能不能往缓存中存值进去?

手动让关闭master,再去看看两个slave还能不能获取缓存的值

在这里插入图片描述
测试结果如下:
(1)获取缓存的值
在这里插入图片描述
在这里插入图片描述
(2)查看slave的replication信息
请添加图片描述请添加图片描述

说明:当master宕机后,slave依然能拿到缓存中的值,并且角色都还是slave,但是失去了master的写操作能咯。没有master,这就会导致数据无法写入了,只能进行读操作。
如何解决?
在哨兵模式出来之前采用的只能是手动去更改了
手动配置slave变成master
将6381改为master
请添加图片描述
将6380的主机(master)从6379改为6381
在这里插入图片描述
查看是否生效:

在这里插入图片描述
在这里插入图片描述
说明手动切换成功
注意:当master宕机后再次恢复(还没有手动修改配置)时,依然是master不会变成slave,和下面的哨兵模式不一样

七、哨兵模式

(0)相关概念

在‘六.3‘’里面有一个master宕机的问题,当时的解决方案是通过命令行去设置新的master以及让其他的slave连接新的master,但是这样很不好,还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性较低,不适用于线上生产环境。

Redis 官方推荐一种高可用方案,也就是 Redis Sentinel 哨兵模式,它弥补了主从模式的不足。Sentinel 通过监控的方式获取主机的工作状态是否正常,当主机发生故障时, Sentinel 会自动进行 Failover(即故障转移),并将其监控的从机提升主服务器(master),从而保证了系统的高可用性。

我的理解就是当master宕机了,且经过哨兵的检测后,哨兵会从剩余的master里面选一个slave来承当master。这中间不需要我们自己动手

  1. 主观下线
    主观下线,适用于主服务器和从服务器。如果在规定的时间内(配置参数:down-after-milliseconds),Sentinel 节点没有收到目标服务器的有效回复,则判定该服务器为“主观下线”。比如 Sentinel1 向主服务发送了PING命令,在规定时间内没收到主服务器PONG回复,则 Sentinel1 判定主服务器为“主观下线”。
  2. 客观下线
    客观下线,只适用于主服务器。 Sentinel1 发现主服务器出现了故障,它会通过相应的命令,询问其它 Sentinel 节点对主服务器的状态判断。如果超过半数以上的 Sentinel 节点认为主服务器 down 掉,则 Sentinel1 节点判定主服务为“客观下线”。
  3. 投票选举
    投票选举,所有 Sentinel 节点会通过投票机制,按照谁发现谁去处理的原则,选举 Sentinel1 为领头节点去做 Failover(故障转移)操作。Sentinel1 节点则按照一定的规则在所有从节点中选择一个最优的作为主服务器,然后通过发布订功能通知其余的从节点(slave)更改配置文件,跟随新上任的主服务器(master)。至此就完成了主从切换的操作。

对上对述过程做简单总结:

Sentinel 负责监控主从节点的“健康”状态。当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来连接 Redis 集群时,会首先连接 Sentinel,通过 Sentinel 来查询主节点的地址,然后再去连接主节点进行数据交互。当主节点发生故障时,客户端会重新向 Sentinel 要地址,Sentinel 会将最新的主节点地址告诉客户端。因此应用程序无需重启即可自动完成主从节点切换。

(1)配置启动哨兵

1.创建sentinel.conf文件,配置哨兵
在这里插入图片描述
2.设置哨兵监视master以及多少个哨兵(sentinel)觉得master挂了就开始选新的master。最后保存退出

# sentinel monitor 名称(随便写) master的ip master的port 
# 最后的数字是当多少个哨兵觉得master挂了就判定挂了
sentinel monitor master 127.0.0.1 6379 1

在这里插入图片描述
3.启动哨兵

./redis-sentinel conf/sentinel.conf

在这里插入图片描述
在这里插入图片描述
查看79的info replication
在这里插入图片描述
查看80的info replication
在这里插入图片描述
查看81的info replication
在这里插入图片描述

(2)测试哨兵是否生效(能否在master挂了自动选新的master)

· 手动关掉master
· 查看剩下的slave有没有新的master诞生

关闭shutdown
在这里插入图片描述
观察sentinel服务的控制台(30s内)
在这里插入图片描述
看到控制台的信息是把6381的slave投票成了新的master了,再去看看info replication的信息是不是这样的
6381:
在这里插入图片描述
6380:
在这里插入图片描述

(3)之前的master修复后再次开启服务是master还是slave?

启动服务:
在这里插入图片描述
变成了salve连接到了6381的master上:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在之前没有去手动更改主从的时候,master回来之后依然是master,但是哨兵模式下是不行的

八、集群

后面补,我的理解就是在哨兵版的主从的集群,多个哨兵,因为单个哨兵也可可能挂掉。

九、缓存穿透、击穿、雪崩

1、缓存穿透

(1)概念:

是指请求的数据在数据库中不存在并且缓存中也不存在,当有大量的这样的请求就会直接绕过(穿透)redis缓存,直接打到数据库上面去,使得redis形同虚设。这种现象就叫做缓存穿透

(2)解决方案:

原因分析: 这种情况主要是因为数据库和缓存都不存在这个数据,而每次的请求都是先看redis缓存中是否存在,不存在再去数据库查询,在的话就直接返回。
解决方案:
第一种:当请求的数据在数据库不存在时,也要在redis中存入(key-null)在后面就能在redis中拿到这个key(虽然值为null),就不会再去数据库中请求了,不过可能有点占内存
第二种:布隆过滤器(布谷鸟过滤器)。布隆过滤器的作用是某个 key 不存在,那么就一定不存在,它说某个 key 存在,那么很大可能是存在(存在一定的误判率)。
上述两个过滤器的详解地址

2、缓存雪崩

(1)概念:

在某一时刻,大量的key突然失效(过期),那么就会导致大量的请求直接打在数据库上面,导致数据库压力巨大,如果在高并发的情况下,可能瞬间就会导致数据库宕机。

(2)解决方案:

分析原因: 大量的key同时失效,要么是过期时间设置的一致,要么是Redis服务可能宕机了
解决方案:
第一种:针对于过期时间上。可以设置不同的过期时间,例如30分钟+一个0-15的随机值,可以实现过期时间在30-45分钟的区间内。但是不能保证百分百预防雪崩
第二种:针对于Redis服务宕机上。可以搭建服务集群。
但是,都不能百分百保证
第三种:设置key永不过期,但是十分消耗内存资源,不太好。

兜底方案:
1.使用熔断机制当流量到达一定的阈值时,就直接返回“系统拥挤”之类的提示,防止过多的请求打在数据库上。至少能保证一部分用户是可以正常使用,其他用户多刷新几次也能得到结果。
2.提高数据库的容灾能力,可以使用分库分表,读写分离的策略。

3、缓存击穿

(1)概念:

跟缓存雪崩有点类似,缓存雪崩是大规模的key失效,而缓存击穿是一个热点的Key有大并发集中对其进行访问,突然间这个Key失效了,导致大并发全部打在数据库上,导致数据库压力剧增。这种现象就叫做缓存击穿。

(2)解决方案:

分析原因: 主要原因就是热点key失效,有大并发,这个时候有两个方案可以考虑,一是对热点key的过期时间操作,二是降低对数据库的访问量
解决方案:
第一种:设置热点key不过期--推荐
第二种:加互斥锁。只有拿到锁才可以查询数据库,降低了在同一时刻打在数据库上的请求,防止数据库打死。但是这样会导致性能降低,可我们使用redis的高可用就是为了性能、效率的。

十、使用jedis连接redis

前提条件是Redis服务已经打开

1、jedis:Java语言的redis客户端工具

2、使用jedis

创建一个普通的maven项目即可

(1)引入jedis依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>redis-jedis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <!-- jedis依赖-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.3.1</version>
        </dependency>
		<!-- json和java对象转换的依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.22</version>
        </dependency>
    </dependencies>
</project>
(2)jedis连接redis

可以选择连接下载在Windows上的redis,也可以连接Linux上安装的redis,只是redis默认是只有本机能连接,需要在其redis.conf 文件中进行修改
修改配置文件:
(1)将下图中的那个注释掉
在这里插入图片描述
(2)把protected-mode yes 改为 protected-mode no
在这里插入图片描述

(3)测试连接
package org.example;

import redis.clients.jedis.Jedis;
public class Main {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.19.129", 6379);
        System.out.println(jedis.ping());
    }
}

运行结果:
在这里插入图片描述
能够ping通说明连接成功

(4)在Java中执行Redis命令
package org.example;

import redis.clients.jedis.Jedis;

/**
 * @Classname Transaction
 * @Description TODO
 * @Version 1.0.0
 * @Date 2023/2/5 13:42
 * @Created by wlh12
 */
public class Transaction {
    public static void main(String[] args) {
        // 连接
        Jedis jedis = new Jedis("localhost", 6379);
        // 清空
        jedis.flushDB();
        // 存list
        jedis.lpush("list","1,2,3,4,5,6,7");
        // list的获取
        System.out.println(jedis.lrange("list",0,-1));
        // 存string
        jedis.mset("money","100","out","0");
        // 开启监听(实现乐观锁)
        jedis.watch("money");
        // 开启事务
        redis.clients.jedis.Transaction multi = jedis.multi();
        // 由于不能保证事务队列中不存在错误,所以使用try catch捕获
        try {
            // 入事务队列
            multi.decrBy("money",10);
            multi.incrBy("out",10);
            // 执行事务队列的所有命令
            int i = 1 / 0; // 模拟一个错误
            multi.exec();
        } catch (Exception e){
            // 出现错误时关闭事务、取消监听
            multi.discard();
            jedis.unwatch();
            // 打印错误
            e.printStackTrace();
        } finally {
            // 无论结果如何打印控制台查看
            System.out.println(jedis.get("money"));
            System.out.println(jedis.get("out"));
        }
    }
}

以上代码执行结果:
在这里插入图片描述
总结:和在redis-cli里面基本一样的命令,也通过监听和事务实现了乐观锁机制,没什么难度

十一、Spring Boot整合Redis

1、创建Spring Boot项目

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
最后刷新maven等待依赖引入

2、引入依赖

<!--        redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

pom完整依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>boot-redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot-redis</name>
    <description>boot-redis</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
    	<!-- spring  boot 启动依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
		<!-- spring 单元测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--        redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3、测试连接使用

(1)在配置文件中配置Redis远程服务的ip、port等信息

在这里插入图片描述

spring:
  redis:
    # Redis服务的ip
    host: 192.168.19.129
    # Redis服务的端口
    port: 6379
    #password: 如果设置了密码的话就需要在这里把密码也配置上
    # 选择Redis的哪一个数据库,默认值为0
    # database: 0
(2)配置RedisConfig实现自定义序列化

不去自定义序列化来覆盖Redis自带的序列化也能使用,但是会有问题,具体的问题可以看下面直接启动去存值效果

测试类:

package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class BootRedisApplicationTests {


    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
        // 获取连接对象
        RedisConnection connection = redisTemplate.getRequiredConnectionFactory().getConnection();
        // 清空缓存
        connection.flushDb();
        // 存入缓存
        redisTemplate.opsForValue().set("key","value");
        // 获取并输出key
        System.out.println(redisTemplate.opsForValue().get("key"));
    }

}

运行结果:
在这里插入图片描述

查看redis-cli看我们存入的什么样子:
在这里插入图片描述
和我存入的key有很大的出入,下面分析一下原因:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
redis的默许是JdkSerializationRedisSerializer
并且,默认的是<object,object>的redistemplate,我们一般需要的是string,object
JdkSerializationRedisSerializer: 运用JDK供应的序列化功用。
自己定义的对象如果要存入缓存的话,对象须要完成Serializable接口。

自定义序列化方案:
RedisConfig :

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

/**
 * @Classname RedisConfig
 * @Description TODO
 * @Version 1.0.0
 * @Date 2023/2/25 12:26
 * @Created by wlh12
 */
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // new 一个String,Object的template
        RedisTemplate<String, Object> template = new RedisTemplate();
        // set连接工厂
        template.setConnectionFactory(redisConnectionFactory);
        // 对于key,我们采用StringRedisSerializer的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 对于value值,因为是object类型的数据,所以不能采用StringRedisSerializer的序列化,而采用其他的
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        // 把配置都放进去
        template.afterPropertiesSet();
        return template;
    }
}

改为<String,Object>
点自动装配按钮,会调到我们自己写的那个bean里面去,说明成功,再启动测试
在这里插入图片描述
测试结果:
在这里插入图片描述
在这里插入图片描述
到此整合完成

(3)RedisTemplate使用

(1)五大基本数据类型的操作
基本和在redis-cli一致,有部分变化
在这里插入图片描述
在这里插入图片描述
(2)其他的(主要是事务)
图中看出,enableTransactionSupport =FALSE说明默认关闭了事务
在这里插入图片描述
正常实现事务提交成功

package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;

@SpringBootTest
class BootRedisApplicationTests {


    // 改为<String,Object>
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Test
    void contextLoads() {
        // 获取连接对象
        RedisConnection connection = redisTemplate.getRequiredConnectionFactory().getConnection();
        // 清空缓存
        connection.flushDb();
        // Strng
        // get
        redisTemplate.opsForValue().set("key","value");
        // set
        String key = (String) redisTemplate.opsForValue().get("key");
        System.out.println(key);
        // 事务
        redisTemplate.execute(new SessionCallback<Object>() {
            // 实现这个方法,这里面就是事务相关的
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                // 开启监听
                redisTemplate.watch("key");
                // 开启事务
                redisTemplate.multi();
                // 修改key的value
                redisTemplate.opsForValue().set("key","newValue");
//                // 模拟一个错误
//                int i = 1/0;
                // 提交事务
                return redisTemplate.exec();
            }
        });
    }
}

运行结果:
在这里插入图片描述
redis-cli:
在这里插入图片描述
模拟出现异常情况
在这里插入图片描述
运行结果:
在这里插入图片描述
redis-cli
在这里插入图片描述
结论:其他的操作基本和redis-cli上差不多的,这个事务稍微有点变化,需要多写一下就行,还有一般来说,不会直接使用Redistemplate,或许会写一个工具类。形如:
在这里插入图片描述

十二、收工

视频参考b站狂神说

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值