文章目录
- String(字符串)【单值单value】
- Hash(哈希,类似java里的Map)
- List(列表)【单key多value且value可重复】
- Set(集合)【单key多value且value不可重复】
- Zset(有序集合)【单key多value且value不可重复,有排序】
后续增加数据类型:bitmap(位图)、hyperloglog(统计)、geo(地理)
String(字符串)【单值单value】
string是redis最基本的类型,一个key对应一个value。string类型是二进制安全的,意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。一个redis中字符串value最大可以是512M。
常用命令
java
set k1 v1
get k1
mset k1 v1 k2 v2
mget k1 k2
incr k3
incrby k3 2
decr k3
decrby k3 2
strlen k3
getrange k1 0 3 如果是字符串,则进行截取、如果是数字,则输出
setrange k1 0 aaaa 从下标0开始赋值,会替代字符串后面的字符,而不是后移
getset k1 v11111 getset(先get再set),前提是该key已经存在
setnx k5 v5 不存在则赋值,存在不赋值
setex k6 5 v6 键秒值,k6的生命周期只有5s
应用场景
1、业务缓存:比如说双十一预期数据库的访问压力陡增,可以利用Redis,提前将要被多次访问的数据放入redis,做到"缓存预热"。让用户进入我们活动页面的时候,先去搜索缓存,不直接访问数据库,做到释放数据库的压力。常见业务伪代码:
java
void cacheData(){
//1.从数据库中获取热点数据
//2.将此类数据序列化
//3.将 (data-data的id) 作为key,序列化的data作为value,利用string的set方法,存入redis。将活动的持续时间作为TTL
}
void getData(id){
//1.将data和id拼接作为key,根据key聪redis中根据string的get指令,进行查询。
//2.1查询到,直接返回
//2.2没有查询到,根据id去数据库中查找,如果有,就直接返回,并存入redis中。
}
分布式锁:比如多个服务去抢夺资源,有并发,线程安全问题。可以利用redis的setnx命令,实现分布式锁的效果,伪代码:
java
void tryLock(id){
//1.不断抢锁直到抢到
while(true){
//1.1.把 (update+传入的id)作为key,当前线程的名称作为value,使用nx指令,设置5s的过期时间(避免因为系统原因未能释放,则导致锁无法释放,这是兜底措施)
//1.2.1.如果1.1步骤失败,说明抢锁失败,进入下一次循环,继续抢锁。
//1.2.2.如果成功,就break,结束循环
}
//2.执行业务逻辑
//3.删除 (update+传入的id)的key的值,相当于释放锁。
}
接口限流: 抢购、秒杀等高并发场景下,流量峰值很高,但是后端业务的资源很有限。解决方案:假如后端资源只够1000qps,那么我们可能就得对高于这个值的qps做限流,高于它的部分可能就得做降级处理了,伪代码如下:
java
void limit(){
//1.取到当前的时间戳
Long now = currentTimeMilles()
//2.将当前服务名+now做为key,每打过来一个请求,就把这个value利用INCR指令+1。
//3.如果当前value > 1000 qps,那么就直接返回"请求限流"
//4.如果 value < 1000 qps,那么执行请求。
}
Hash(哈希,类似java里的Map)
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似Java里面的Map<String,Object>
常用命令:
java
hset user id 11
hget user id
hgetall user
hmset stu name zhupeng age 23
hmget student age name 批量设置属性/批量获取属性值
hdel user id 删除指定属性
hexists user id 判断key里面的某个值的key
hkeys user 查询所有key值
hvals user 查询所有value值
hlen user 查询key长度
hincrby user id 2 value值加num
hincrbyfloat user score 0.5
hsetnx user age 27 字段不存在则加入
应用场景:
对象数据存储场景:用户信息、商品信息、文章信息、购物车信息,比如购物车:
新增商品:hset shopcar:uid1024 334488 1
新增商品:hset shopcar:uid1024 334477 1
增加商品数量:hincrby shopcar:uid1024 334477 1
商品总数:hlen shopcar:uid1024
全部选择:hgetall shopcar:uid1024
List(列表)【单key多value且value可重复】
与其说list是一个集合,不如说是一个双端队列(双向列表),可以从列表的头部(左边)或者尾部(右边)插入或读取元素,支持反向查找和遍历,不过也带来了额外的内存开销。

常用命令:
java
lpush list01 1 2 3 4 5 类似入栈
lpop list01 从栈上边、队列左边读 // 5
rpop list01 从栈下边、队列右边读 // 1
rpush list02 1 2 3 4 5 类似入队列
lpop list02 从栈上边、队列左边读 // 1
rpop list02 从栈下边、队列右边读 // 5
lset list01 0 111 给指定下标赋值,也即是替换
linsert list01 before/after 1 java 在制定元素22之前/之后插入元素java
lrange list01 0 -1 从栈上边、队列左边开始查询集合list01 // 1 2 3 4 5
lindex list01 1 按照索引下标获得元素(从栈上边、队列左边读)
llen list01 list01长度
lrem list01 2 3 删除list01的2个3
ltrim list01 0 3 截取指定范围的值后再赋值给key
rpoplpush list01 list02 rpoplpush 源列表 目的列表
应用场景
1、消息队列:可以用来做消息队列,只是功能过于简单且存在很多缺陷,不建议这样做。相对来说,Redis 5.0 新增加的一个数据结构 Stream 更适合做消息队列一些,只是功能依然非常简陋。和专业的消息队列相比,还是有很多欠缺的地方比如消息丢失和堆积问题不好解决。
2、点赞提醒:场景复现:我是一个掘金作者,当有掘友给我点赞的时候,我需要接收到点赞信息,并且给予反馈。解决方案:后端在接受点赞消息后,将点赞人push到点赞List中,当我(掘金作者)登录网站的时候,前端给后端请求点赞的list。
java
void likeList(){
String listName = "like-" + articleId
//开启一个线程,模拟用户端点赞,此时有10000人
for(int i=0;i<10000;i++){
//将listName作为list的key,用户id作为value,利用rpush指令,加入list
}
//再开启一个线程,模拟掘金作者端
while(true){
//1.利用LRANGE指令,拉取前1000个人的点赞。
//2.读取,并且展示。
//3.展示完成后,利用LTRIM指令,把第一步返回的userId的size大小作为下标1,-1作为下标2,执行该指令。相当于把前1000个userIds截断掉
}
}
性能总结:
它是一个字符串链表,left、right都可以插入添加;
如果键不存在,创建新的链表;
如果键已存在,新增内容;
如果值全移除,对应的键也就消失了。
链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。
Set(集合)【单key多value且value不可重复】
Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一,有点类似于 Java 中的 HashSet 。当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个元素是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
常用命令
java
sadd set01 1 1 2 3 4 4 添加set01= 1 2 3
smembers set01 查看set所有元素【不能用get】
sismember set01 1 查看1是否是set01内元素【0不是,1 是】
scard set01 获取集合里面的元素个数
srem set01 1 删除集合中元素
srandmember set01 3 从集合中随机显示3个整数
spop set01 集合中元素随机出栈
smove set01 set02 3 作用是将key1里的某个值赋给key2
sdiff set01 set02 差集,属于set01,不属于set02
sinter set01 set02 交集
sunion set01 set02 并集
应用场景
需要存放的数据不能重复的场景:网站UV 统计(数据量巨大的场景还是 HyperLogLog更适合一些)、文章点赞、动态点赞等场景。
相关命令:SCARD(获取集合数量) 。
需要获取多个数据源交集、并集和差集的场景:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集) 等场景。
相关命令:SINTER(交集)、SINTERSTORE (交集)、SUNION (并集)、SUNIONSTORE(并集)、SDIFF(差集)、SDIFFSTORE (差集)。
需要随机获取数据源中的元素的场景:抽奖系统、随机点名等场景。
相关命令:SPOP(随机获取集合中的元素并移除,适合不允许重复中奖的场景)、SRANDMEMBER(随机获取集合中的元素,适合允许重复中奖的场景)。
Zset(有序集合)【单key多value且value不可重复,有排序】
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
常用命令
java
zadd zset01 60 v1 70 v2 80 v3 增加
zrange zset01 0 -1 查询,不包括分数score
zrange zset01 0 -1 withscores 查询,包括分数score
zrangebyscore zset01 60 90 查询[60, 90]的value
zrangebyscore zset01 60 (90 查询[60, 90)的value
zrangebyscore zset01 (60 (90 查询(60, 90)的value
zrangebyscore zset01 60 90 limit 2 2 limit 开始下标步 多少步[Limit 作用是返回限制]
zrem zset01 v3 删除某score下对应的value值
zcard zset01 查询个数
zrank zset01 v1 查询下标
zrevrank key values值,作用是逆序获得下标值
zrevrange
zrevrangebyscore key 结束score 开始score
应用场景
需要随机获取数据源中的元素根据某个权重进行排序的场景:各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。
相关命令:ZRANGE (从小到大排序)、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。
需要存储的数据有优先级或者重要程度的场景:比如优先级任务队列。
相关命令:ZRANGE (从小到大排序)、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。