Redis学习笔记

目录

1、认识Redis

Redis能干嘛?

特性

2、基础知识

Redis是单线程的

Redis为什么单线程还这么快?

3、Redis五大数据类型

1、String

2、List

3、Set

4、Hash

5、Zset

4、Redis三种特殊数据类型

1、geospatial

2、hyperloglog

3、Bitmaps

5、Redis事务

6、Redis实现乐观锁

7、Jedis

8、SpringBoot集成Redis

整合测试

自定义RedisTemplate

9、Redis.conf 详解

10、Redis的持久化

1、RDB(Redis DataBase)

2、AOF(Append Only File)

11、Redis发布订阅

12、Redis主从复制

概念

环境配置

一主二从 

方式一:命令配置 (临时)

方式二:配置文件 (永久)

复制原理

宕机后手动配置主节点

13、哨兵模式(自动选举老大的模式)

哨兵模式的全部配置

14、Redis的缓存穿透与雪崩(面试高频,工作常用~)

缓存穿透

概念

解决方案

缓存击穿

概念

解决方案

缓存雪崩

概念

解决方案


1、认识Redis

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis能干嘛?

1、内存存储、持久化,内存中的数据是断电即失的,所以持久化很重要(RDB、AOF)
2、效率高,可以用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器、计数器(浏览量)
6、……

特性

1、多样的数据类型
2、持久化
3、集群
4、事务
……

2、基础知识

1、redis默认有16个数据库,默认使用的是第0个数据库,可以使用select切换数据库

select 1  #切换1数据库
DBSIZE  #查看DB大小
keys *  #查看所有key
flushall #清空所有数据库
flushdb #清空当前数据库
exists key #判断当前key是否存在
move key 1 #移除当前的key
expire key second #设置过期时间
ttl key  #查看key剩余过期时间
type key #查看key的类型

Redis是单线程的

官方表示,Redis是基于内存操作的,CPU不是Redis的性能瓶颈。Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程,就使用单线程了

Redis是C语言写的,官方提供的数据为100000+的QPS,完全不比同样使用key-value的MemeCache差

Redis为什么单线程还这么快?

误区1:高性能服务器一定是多线程的
误区2:多线程(CPU上下文切换)一定比单线程效率高

速度:CPU>内存>硬盘
核心:redis是将全部数据放在内存中,所以使用单线程去操作效率就是最高的,对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都是在一个CPU上。

3、Redis五大数据类型

1、String

set key value #设置key-value
get key  #获取key的value
exists key  #key是否存在
append key value #追加字符串,若key不存,相当于set key value
strlen key #获取字符串长度
incr key #当前key的value加1
decr key #当前key的value减一
incrby key 10 #当前key加10
decrby key 10 #当前key减10
getrange key 0 3 #字符串范围 (getrange key 0 -1 获取全部字符串)
setrange key 1 xx #替换指定位置开始的字符串
setex key second value    #(set with expire)设置过期时间
setnx key value   #(set if not with exists )不存在再设置 (分布式锁中常使用)
mset key1 v1 key2 v2  #批量设置
mget key1 key2 key3  #批量获取
msetnx key1 v1 key2 v2  #不存在再设置(批量 原子性操作  一起成功 一起失败)
getset key value #先获取原值再设置新值
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> set name lqh 
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set age 1 
OK
127.0.0.1:6379> keys *  #查看所有的key
1) "age"
2) "name"
127.0.0.1:6379> EXISTS key
(integer) 0
127.0.0.1:6379> EXISTS name #判断当前key是否存在
(integer) 1
127.0.0.1:6379> move name 1 #将key移动到1号数据库中
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name 123
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> EXPIRE name 10 #设置key过期的时间,单位是秒
(integer) 1
127.0.0.1:6379> ttl name #查看当前key的剩余时间
(integer) 6
127.0.0.1:6379> set name lqh
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> TYPE name #查看当前key对应value的类型
string
127.0.0.1:6379> TYPE age
string
127.0.0.1:6379> set key1 v1  #设置值
OK
127.0.0.1:6379> get key1  #获得值
"v1"
127.0.0.1:6379> keys *  #获得所有key
1) "key1"
2) "name"
3) "age"
127.0.0.1:6379> EXISTS key1  #判断某一个key是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello"  #追加字符串,如果key不存在就相当于set key
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> APPEND key1 ",nihao"  
(integer) 13
127.0.0.1:6379> STRLEN key1  #获取字符串长度
(integer) 13
127.0.0.1:6379> get key1
"v1hello,nihao"
#步长
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views  #自增一
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views  #自减一
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> INCRBY views 10  #设置步长,指定增量
(integer) 9
127.0.0.1:6379> DECRBY views 5   #设置步长,指定减量
(integer) 4
127.0.0.1:6379> get views
"4"
#字符串范围
127.0.0.1:6379> set key1 "hello,lqh"  #设置key的值
OK
127.0.0.1:6379> get key1
"hello,lqh"
127.0.0.1:6379> GETRANGE key1 0 3  #截取字符串  [0,3]
"hell" 
127.0.0.1:6379> GETRANGE key1 0 -1  #获取全部的字符串 和get key是一样的
"hello,lqh"
#替换
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE key2 1 xx  #替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
#setex key #(set with expire)设置过期时间
#setnx key #(set if not with exists )不存在再设置 在分布式锁中会常使用
127.0.0.1:6379> setex key3 30 "hello"  #设置一个key3的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) 19
127.0.0.1:6379> setnx mykey "redis"  #如果mykey不存在,创建mykey
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
2) "key1"
3) "key2"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey "hello"  #如果mykey存在,创建失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"
mset key1 v1 key2 v2  #批量设置
mget key1 key2 key3  #批量获取

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3  #同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4  #msetnx是一个原子性的操作,要么一起成功要么一起失败
(integer) 0
127.0.0.1:6379> get k4
(nil)

#对象
set user:1 {name:zhangsan,age:2} #设置一个user:1对象,值为json字符来保存一个对象

#这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在redis中是完全ok的
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"

getset #先get再set

127.0.0.1:6379> getset db redis  #如果不存在值则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db Mongodb #如果存在值,获取原来的值并设置新的值
"redis"
127.0.0.1:6379> get db
"Mongodb"

数据结构是相同的

String类似的使用场景:value除了是我们的字符串还可以使我们的数字(计数器、统计多单位数量、粉丝数、对象缓存存储)

2、List

Redis中,可以将list用作栈、队列、阻塞队列的数据结构
所有list命令都是以l开头

lpush key v1 v2 ...  #将一个值或多个值插入列表的头部(左)
rpush key v1 v2 ...  #将一个值或多个值插入列表的尾部(右)
lrange key start end  #用过区间获取具体的值  (0 -1 区间获取全部值)
lpop key  #移除列表头部第一个值(左)
rpop key  #移除列表尾部第一个值(右)
lindex key index #通过索引获取值
llen key   #获取列表长度
lrem key count value  #移除list集合中指定个数的value  精确匹配
ltrim key start stop   #通过下标截取指定长度,list已经改变,只剩下截取后的元素
rpoplpush key otherkey  #移除列表中最后一个元素,并将它插入另一个列表头部
lset key index value  #将列表中指定下标的值替换为另外一个值,更新操作 (如果列表或索引不存在  会报错)
linsert key before v1 v2  #在v1前插入v2
linsert key after v1 v2  #在v1后插入v2
127.0.0.1:6379> LPUSH list one  #将一个或者多个值,插入到列表的头部(左边)
(integer) 1
127.0.0.1:6379> LPUSH list twe
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1  #获取list中的值
1) "three"
2) "twe"
3) "one"
127.0.0.1:6379> LRANGE list 0 1  #通过区间获取list中具体的值
1) "three"
2) "twe"
127.0.0.1:6379> RPUSH list right  #将一个或者多个值,插入到列表的尾部(右边)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "twe"
3) "one"
4) "right"
#LPOP
#RPOP
127.0.0.1:6379> LRANGE list 0 -1 
1) "three"
2) "twe"
3) "one"
4) "right"
127.0.0.1:6379> LPOP list #移除list的第一个元素
"three"
127.0.0.1:6379> RPOP list #移除list的最后一个元素
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "twe"
2) "one"
#lindex
127.0.0.1:6379> LRANGE list 0 -1
1) "twe"
2) "one"
127.0.0.1:6379> LINDEX list 1  #通过下标获得list中的某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"twe"

127.0.0.1:6379> Lpush list one
(integer) 1
127.0.0.1:6379> Lpush list twe
(integer) 2
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> Llen list  #返回列表长度
(integer) 3
#移除指定的值
127.0.0.1:6379> Lpush list one
(integer) 1
127.0.0.1:6379> Lpush list twe
(integer) 2
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> Llen list
(integer) 3
127.0.0.1:6379> Lpush list three
(integer) 4
127.0.0.1:6379> lrem list 1 one #移除list集合中指定个数的valus,精确匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "twe"
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "twe"
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "twe"
127.0.0.1:6379> lrem list 2 three
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "twe"
#ltrim 修剪

127.0.0.1:6379> Lpush mylist "hello"
(integer) 1
127.0.0.1:6379> Lpush mylist "hello1"
(integer) 2
127.0.0.1:6379> Lpush mylist "hello2"
(integer) 3
127.0.0.1:6379> Lpush mylist "hello3"
(integer) 4
127.0.0.1:6379> ltrim mylist 1 2  #只截取区间内的,剩余的将全部被删除
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello2"
2) "hello1"
rpoplpush  #移除列表中最后一个元素,并将它移动到新的列表中

127.0.0.1:6379> lpush list "hello"
(integer) 1
127.0.0.1:6379> lpush list "hello1"
(integer) 2
127.0.0.1:6379> lpush list "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush list mylist  #移除列表中最后一个元素,并将它移动到新的列表中
"hello"
127.0.0.1:6379> lrange list 0 -1  #查看原来的列表
1) "hello2"
2) "hello1"
127.0.0.1:6379> lrange mylist 0 -1  #查看目标列表中却是存在该值
1) "hello"
lset #将列表中指定下标的值替换为另外一个值
 
127.0.0.1:6379> EXISTS list  #判断这个列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item  #如果不存在我们去更新就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value1"
127.0.0.1:6379> lset list 0 item  #如果存在则更新下标的值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 other  #如果不存在就会报错
(error) ERR index out of range
linsert #将某个具体的value插入到列表中某个元素的前面或者后面

127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list world
(integer) 2
127.0.0.1:6379> LINSERT list before "world" "other" #在world前插入other
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> lpush mylist hello
(integer) 1
127.0.0.1:6379> lpush mylist world
(integer) 2
127.0.0.1:6379> LINSERT mylist before "world" "other"
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "other"
2) "world"
3) "hello"
127.0.0.1:6379> LINSERT list after "world" "123" #在world后插入123
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
4) "123"

3、Set

set中的值不能重复

sadd key value  #添加元素
smembers key   #查看指定set中所用元素
sismember key value  #判断某一个值在指定set中是否存在
scard key  #获取set中的内容元素个数
srem key value   #移除set中指定元素
srandmember key count  #随机选出指定个数的成员
spop key  #随机移除元素
smove oldkey  newkey member  #将一个指定的值,从一个set移动到另一个set
sdiff key...   #获取多个set差集
sinter key...  #获取多个set交集 (共同好友、共同关注)
sunion key...  #获取多个set并集
127.0.0.1:6379> sadd myset hello  #添加元素
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset 123
(integer) 1
127.0.0.1:6379> SMEMBERS myset  #查看指定set中所用元素
1) "123"
2) "world"
3) "hello"
127.0.0.1:6379> SISMEMBER myset hello #判断某一个值在指定set中是否存在
(integer) 1 
127.0.0.1:6379> SISMEMBER myset lqh
(integer) 0
127.0.0.1:6379> SCARD myset  #获取set集合里元素的个数
(integer) 3
127.0.0.1:6379> srem myset 123  #移除set中的指定
(integer) 1
127.0.0.1:6379> SCARD myset
(integer) 2
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SRANDMEMBER myset  #随机选出指定个数的成员
"world"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"world"

127.0.0.1:6379> SMEMBERS myset
1) "def"
2) "abc"
3) "world"
4) "hello"
127.0.0.1:6379> spop myset  #随机移除元素
"def"
127.0.0.1:6379> spop myset
"hello"
#将一个指定的值,从一个set移动到另一个set
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset lqh
(integer) 1
127.0.0.1:6379> sadd myset2 set2
(integer) 1
127.0.0.1:6379> smove myset myset2 lqh #将一个指定的值,从一个set移动到另一个set集合中
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SMEMBERS myset2
1) "set2"
2) "lqh"
127.0.0.1:6379> sadd key1 1
(integer) 1
127.0.0.1:6379> sadd key1 2
(integer) 1
127.0.0.1:6379> sadd key1 3
(integer) 1
127.0.0.1:6379> sadd key2 3
(integer) 1
127.0.0.1:6379> sadd key2 4
(integer) 1
127.0.0.1:6379> sadd key2 5
(integer) 1
127.0.0.1:6379> sadd key2 6
(integer) 1
127.0.0.1:6379> SDIFF key1 key2  #差集
1) "1"
2) "2"
127.0.0.1:6379> SINTER key1 key2  #交集 共同好友可以这么实现
1) "3"
127.0.0.1:6379> SUNION key1 key2  #并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"

应用场景:微博,将用户所有关注放入一个set,粉丝放入一个set
-> 共同关注、二度好友、相互关注…..

4、Hash

Map集合 key-(key-value)

hs
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值