Redis笔记
一、什么是Redis
基本概念
redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库(非关系性数据库)。
redis的优势
- 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
- 支持丰富数据类型,支持string,list,set,sorted set,hash
- 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
- 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
基础知识
16个数据库,默认是0个;
select 3
disize
flushdb
flushAll
二、redis的应用场景
缓存
(1) 对于一些要返回给前端数据的缓存,当有大量数据库sql操作时候,为了避免每次接口请求都要去查询数据库,可以把一些数据缓存到redis中,这样是直接从内存中获取数据,速度回增快很多。
(2) web端用户,用于登陆缓存session数据,登陆的一些信息存到session中,缓存到redis中
队列
redis中提供了list接口,这个list提供了lpush和rpop,这两个方法具有原子性,可以插入队列元素和弹出队列元素。
数据存储
redis是非关系型数据库,可以把redis直接用于数据存储,提供了增删改查等操作,因为redis有良好的硬盘持久化机制,redis数据就可以定期持久化到硬盘中,保证了redis数据的完整性和安全性。
redis锁实现防刷机制
redis锁可以处理并发问题,redis数据类型中有一个set类型,set类型在存储数据的时候是无序的,而且每个值是不一样的,不能重复,这样就可以快速的查找元素中某个值是否存在,精确的进行增加删除操作。
三、redis的基本数据类型
redis是一种高级的key-value非关系型数据库。其中value支持五种数据类型:string,List,set,hash,sore set
一、字符串(string)
string存储的元素类型可以是string/int/float,int类型可以进行增加和减少操作。
代码实际操作过程:
set key1 v1 # 设置值
get key1 # 获取值
keys * # 获取所有的key
exists key1 # 判断一个key是否存在
append key1 "hello" # 追加字符串,若当前key不存在,就相当于setkey
strlen key1 # 获取字符串的长度
# ================================================================================
# i++
# 步长 i+=
set views 0 # 处置浏览量为0
incr views # 自增1
incrby views 10 # 设置步长,指定增量
decrby views 10 # 设置步长,指定增量
# ================================================================================
# 字符串范围 range
set key1 "hello,world" # 设置key1 的值
getrange key1 0 3 #截取字符串 [0,3],是闭区间
getrange key1 0 -1 # 获取全部的字符串 和 get key 是一样的
# ================================================================================
# 替换 replace
set key2 abcdefg
setrange key2 1 xx # 从指定位置开始的字符串 替换
get key2
"axxdefg"
# ==================================================================================
# setex (set with expire) # 设置过期时间 ---秒
# setnx (set if not exist) # 不存在设置 (在分布式锁中会经常使用!)
setex key3 30 "hello" # 设置key3 的值为hello,30秒后过期
ttl keys # 查看当前key 还有多久过期
setnx mykey "redis" # 若mykey 不存在,则创建 mykey
setnx mykey "mongoDB" # 若mykey 存在,则创建 失败!
# =======================================================================================
# mset # 同时设置多个值
# mget
mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
mget k1 k2 k3 # 同时获取多个值
msetnx k1 v1 k4 v4 # msetnx 是一个原子性的操作,要么一起成功,要么一起失败!
# ==========================================================================================
# 对象
set user:1 {name:zhangsan,age:3} # 设置一个user:1 对象,值为 JSON 字符来保存一个对象!
# 这里的key 是一个巧妙的设计:user:{id}:{field},如此设计在Redis中时完全OK了!
mset user:1:name zhangsan user:1:age 2
mget user:1:name user:1:age
"zhangsan"
"2"
# ==========================================================================================
# getset # 先get 然后 set
getset db redis # 如果不存在值,则返回 nil
get db
"redis"
getset db mongodb # 若存在值,获取原来的值,并设置新的值
"redis"
get db
"mongodb"
# ==========================================================================================
String使用场景
String使用场景:value除了是我的字符串还可以是我们的数字!
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储!
二、列表(list)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRzCGSLG-1640009772282)(C:\Users\小王子\AppData\Roaming\Typora\typora-user-images\image-20211213194155642.png)]
在Redis中可以把list 完成,栈、队列、阻塞队列!
所有的list 命令都是以 l 开头的!redis 不区分大小写命令!
list类型是一个有序的列表,有序表示的是从左到右还是从右到左,而且数据内容是可以重复的。
代码实际操作过程:
# ===============================================================================================
lpush list one # 将一个值或多个值,插入到列表头部(左)
lrange list 0 -1 # 获取list 中的值!
lrange list 0 1 # 通过区间获取具体的值!
rpush list right # 将一个值或多个值,插入到列表尾部(右)
# ===============================================================================================
lpop
rpop
lpop list #移出list 的第一个元素
rpop list #移出list 的最后一个元素
# ===============================================================================================
index
index list 1 #通过下标获得 list 中的某一个值!
# ===============================================================================================
llen
llen list # 返回列表的长度
# ===============================================================================================
lrem
lrem list 1 one # 移出list 集合中指定个数的value,精确匹配
# ===============================================================================================
trim # 修剪; list 截取!
rpush mylist "hello"
rpush mylist "hello1"
rpush mylist "hello2"
rpush mylist "hello3"
ltrim mylist 1 2 # 通过下标截取指定的长度,这个list 已经被改变了,截断了只剩下截取的元素了!
lrange mylist 0 -1
"hello1"
"hello2"
# ===============================================================================================
rpoplpush # 移出列表最后一个元素,将它移动到新的列表中!
rpush mylist "hello"
rpush mylist "hello1"
rpush mylist "hello2"
rpoplpush mylist myotherlist # 移出列表最后一个元素,将它移动到新的列表中!
lrange mylist 0 -1 # 查看原来的列表
"hello"
"hello1"
lrange myotherlist 0 -1 # 查看目标列表中,确实存在该字段!
"hello2"
# ===============================================================================================
lset # 将列表中指定下标的值替换为另一个值,更新操作!
exists list # 判断这个列表是否存在
lset list 0 item #若不存在列表,我们去更新就会报错!
lpush list value1
lset list 0 item # 若存在,更新当前下标的值
lset list 1 other #若不存在列表,我们去更新就会报错!
# ===============================================================================================
linsert # 将某个具体的value 插入到列表中某个元素的前面或后面
rpush mylist "hello"
rpush mylist "world"
linsert mylist before "world" other # 将某个具体的value 插入到列表中某个元素的前面
lrange mylist 0 -1
"hello"
"other"
"world"
linsert mylist after world new # 将某个具体的value 插入到列表中某个元素的后面
"hello"
"other"
"world"
"new"
# ===============================================================================================
小结:
- 它实际上是一个链表,before Node after, left ,right 都可以插入值
- 若key 不存在,创建新的链表
- 若key 存在,新增内容
- 若移出了所有值,空链表,也代表不存在!
- 在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点~
消息排队!消息队列(Lpush Rpop), 栈(Lpush Lpop)
三、集合(set)
set类型中提供了无序的方式来存储多个不同的元素,set类型中每个元素的值都不一样,用户可以快速对元素中的值添加删除,检查某些值是否存在,重复的元素是无法继续插入集合的。
代码实际操作过程:
127.0.0.1:6379> sadd set1 12 # 添加set元素,重复元素不再添加
(integer) 1
127.0.0.1:6379> sadd set1 12
(integer) 0
127.0.0.1:6379> scard set1
(integer) 1
127.0.0.1:6379> sadd set1 13
(integer) 1
127.0.0.1:6379> scard set1 # scard计算元素总数
(integer) 2
127.0.0.1:6379> sadd set1 13
(integer) 0
127.0.0.1:6379> smembers set1 # 查看指定key集合元素
127.0.0.1:6379> sismember set1 13 # 查看13是否在集合中,返回1 表示存在 返回0表示不存在
(integer) 1
127.0.0.1:6379> srem set1 13 # 从集合中删除13
# ===============================================================================================
# sdiff计算差集
127.0.0.1:6379> sadd set2 a b c
(integer) 3
127.0.0.1:6379> sadd set3 b c d e
(integer) 4
127.0.0.1:6379> sdiff set2 set3
1) "a"
127.0.0.1:6379> sdiff set3 set2
1) "d"
2) "e"
# 我们发现 集合的顺序不同 结果不一
# ===============================================================================================
# sinter计算交集
127.0.0.1:6379> sinter set2 set3
1) "c"
2) "b"
四、哈希(hash)
hash类型也叫散列类型,存储的时候存的是键值对。查询条数的时候只要是健不一样,就是不同的条数,尽管值是相同的。
[root@VM_160_197_centos /]# redis-cli
127.0.0.1:6379> hset hash1 key1 12
(integer) 1
127.0.0.1:6379> hget hash1 key1
"12"
127.0.0.1:6379> hset hash1 key2 13
(integer) 1
127.0.0.1:6379> hset hash1 key3 13
(integer) 1
127.0.0.1:6379> hlen hash1 # 查询条数的时候只要是健不一样,就是不同的条数,尽管值是相同的。
(integer) 3
127.0.0.1:6379> hset hsah1 key3 14
(integer) 1
127.0.0.1:6379> hset hash1 key3 14
(integer) 0
127.0.0.1:6379> hget hash1 key3
"14"
127.0.0.1:6379> hmget hash1 key1 key2 # 同时获取key1和key2的值
1) "12"
2) "13"
五、有序集合(sort set)zset
sore set也叫有序分数集,可以把它看作一个排行榜,每一个同学都有自己的分数,且排行榜中还有一个排名的属性,排行属性从0,根据分数不断变大,排行也不断变大。
,这个类型有点复杂,上一张图吧。
sort set特性
1)sore set中的值是全局唯一的。
一个值设置了之后,再次设置不会增加,只会覆盖修改。
2)如果有两条分数相同,排名应该怎那么看?
如果两个分数值相同,会根据值两个元素变量名的字典排序顺序排列先后,可看下方操作代码。
代码实际操作过程:
Map集合,key-Map!只是这个值是一个map集合,本质和String类型没有太大区别,还是以个简单的key-value
flushdb # 清空当前数据库
flushall # 清空所有数据库
hset myhash field1 wanglin # set一个具体的key-value
hget myhash field1 # 获取一个字段值
hmset myhash field1 hello field2 world # set多个 key-value
hmget myhash field1 field2 # 获取多个字段值
hgetall myhash # 获取全部的数据
hdel myhash field1 # 删除hash指定key字段
hlen myhash # 获取hash表的字段长度
hexists myhash # 判断hash中指定字段是否存在
hkeys myhash # 获取所有的key
hvals myhash # 获取所欲的值
hset myhash field3 5 # 指定增量
hsetnx myhash field4 hello # 如果不存在则可以设置,若存在则不能设置
注意:
hash变更的数据 user name age,尤其是用户信息之类的,经常变动的信息!hash 更适合与对象的存储,String 更适合字符串存储!
127.0.0.1:6379[1]> zadd zset1 10.1 val1 //添加一个值和分数
(integer) 1
127.0.0.1:6379[1]> zadd zset1 11.1 val2
(integer) 1
127.0.0.1:6379[1]> zadd zset1 9.2 val3
(integer) 1
127.0.0.1:6379[1]> zcard zset1 //统计当前key下值的个数
(integer) 3
127.0.0.1:6379[1]> zrange zset1 0 2 withscores //查看0到2的所有值和分数按照排名
1) "val3"
2) "9.1999999999999993"
3) "val1"
4) "10.1"
5) "val2"
6) "11.1"
127.0.0.1:6379[1]> zrank zset1 val2
(integer) 2
127.0.0.1:6379[1]> zadd zset1 12.2 val3 //覆盖iu该val3
(integer) 0
127.0.0.1:6379[1]> zrange zset1 0 2 withscores//查看0到2的所有值和分数按照排名
1) "val1"
2) "10.1"
3) "val2"
4) "11.1"
5) "val3"
6) "12.199999999999999"
127.0.0.1:6379[1]> zadd zset1 12.2 val2
(integer) 0
127.0.0.1:6379[1]> zrange zset1 0 2 withscores//这时候有两个分数相同,查看0到2的所有值和分数按照排名
1) "val1"
2) "10.1"
3) "val2"
4) "12.199999999999999"
5) "val3"
6) "12.199999999999999"
四、Redis常用命令
# 查看安装是否成功:
rpm –qa|grep gcc
# 后台启动后,查看服务:
netstat –anp|grep 6379
五、Redis基本环境
安装
六、哨兵模式
七、Redis穿透和雪崩
服务的高可用问题
导致原因
查不到数据导致的
布隆过滤器
缓存空对象
缓存击穿
击穿原因
量太大,缓存过期