学习Redis五大数据类型首先学习一下Redis的基础知识:
基础知识
redis默认有16个数据库
默认使用的是第0个
可以使用select 数据库编号
进行切换数据库
查看数据库大小:dbsize
不同的数据库内容不共享
查看所有的key:keys *
清除当前数据库:flushdb
清除全部数据库的内容:flushall
为什么redis的端口是6379?
是一个女明星的名字九宫格打出来的数字。
Redis是单线程的!
Redis是很快的。官方表示,Redis是基于内存操作,cpu不是Redis性能瓶颈,Redis性能瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就是用单线程了。
Redis是c语言写的,官方提供的数据为:100000+的QPS,完全不比同样是使用key-value的Memecache差!
Redis为什么单线程还这么快?
-
误区1:高性能的服务器一定是多线程的?
-
误区2:多线程(CPU上下文切换)一定比单线程效率高?
速度比较:CPU>内存>硬盘
核心:Redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换:耗时的操作!!!)对于内存系统来说,如果没有上下文切换效率就是最高的,在内存情况下,这个就是最佳方案。
五大数据类型
官方文档
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
Redis-Key
exists keyname # 判断当前key是否存在
move keyname 1 # 移除当前的key 这里的1是移除哪个数据库中的键值对,从1开始
expire keyname time(秒) # 设置过期时间
ttl keyname # 查看当前key的剩余过期时间
get key # 获得key的值
type keyname # 查看当前key的一个类型
后期如果遇到不会的命令,可以在官网查看帮助文档
一、String(字符串)
set key1 v1 # 设置值
get key1 # 获取值
keys * # 获取所有的key
exists key1 # 判断key1是否存在
append key1 “hello” # 追加字符串,如果当前key1不存在,就相当于 set key1
strlen key1 # 获取字符串的长度
#############################################################################
# i++
set views 0 # 初始浏览量为0
incr views # 自增1 浏览量+1
decr views # 自减1 浏览量-1
incrby views 10 # 步长 自增10 浏览量+10
decrby views 10 # 步长 自减10 浏览量-10
#############################################################################
# 字符串范围 range
set key1 "hello,lyt" # 设置key1的值
getrange key1 0 3 # 截取字符串 [0, 3]
getrange key 0 -1 # 获取全部的字符串和get key1是一样的
# 替换 replace
set key2 abcdefg
get key2 返回abcdefg
setrange key2 1 xx # 替换指定位置开始的字符串
get key2 返回axxdefg
#############################################################################
# setex(set with expire) 设置过期时间 单位秒
# setnx(set if not exist) 不存在在设置 (在分布式锁中会常常使用)
setex key1 30 "hello" # 设置key1的值为hello,30秒后过期
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}:{filed},如此设计在redis中是完全OK的
mset user:1:name zhangsan user:1:age 3
mget user:1:name user:1:age 输出 "zhangsan" "3"
#############################################################################
# 组合命令
getset # get在set
getset db redis # 如果不存在值,则返回nil。并设置值
getset db MongoDB # 如果存在值,获取原来的值。并设置新的值
数据结构是相同的!
String类型的使用场景:value除了是字符串还可以是数字。
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
二、 List(列表)
基本的数据类型:列表
在redis里面,我们可以把list完成,栈、队列、阻塞队列!
所有的list命令都是用“l”开头的,Redis不区分大小写命令。
#############################################################################
# 插入命令 lpush rpush
lpush list one # 将一个值或者多个值,插入到列表头部(左)
rpush list right # 将一个值或者多个值,插入到列表的尾部(右)
lrange list 0 -1 # 获取list中的值
lrange list 0 1 # 通过区间获取具体的值
#############################################################################
# 移除命令 lpop rpop
lpop list # 移除list的第一个元素 返回移除元素的值
rpop list # 移除list的最后一个元素 返回移除元素的值
#############################################################################
# 取值 lindex
lindex list 1 # 通过下标获得list中的某一个值
#############################################################################
# 列表长度 llen
llen list # 返回列表的长度
#############################################################################
# 移除指定的值 lrem (场景:取关)
lrem list 1 one # 移除list列表中指定个数的value,精确匹配
#############################################################################
# 截取指定长度 ltrim 修剪
ltrim mylist 1 2 # 通过下标截取指定的长度,这个list已经被改变了,截断了只剩下截取的元素
#############################################################################
# 组合 rpoplpush # 移除列表的最后一个元素,将他移动到新的列表中
rpoplpush mylist myotherlist # 移除列表的最后一个元素,将他移动到新的列表中
lrange myotherlsit 0 -1 # 查看目标列表中,确实存在该值
#############################################################################
# 将列表中指定下标的值替换为另外一个值,相当于更新操作 lset (前提:列表中有这个下标)
exists list # 判断列表是否存在
lset list 0 item # 如果不存在列表我们去更新就会报错(error) ERR no such key没有这样的key
lset list 0 item # 如果存在,更新当前下标的值
#############################################################################
# 将某个具体的value插入到列表中某个元素的前面或后面 linsert
linsert mylist before "列表中的元素" "要插入的value" # 把value插入到元素之前
linsert mylist after "列表中的元素" "要插入的value" # 把value插入到元素之后
小结
- 实际上是一个链表,before Node after,left ,right都可以插入值
- 如果key不存在,创建新链表
- 如果key存在,新增内容
- 如果移除了所有的值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高。中间元素,相对来说效率会低一点
消息排队!消息队列(lpush rpop) 栈(lpush lpop)
三、Set(集合)
set中的值是不能重复的。无序不重复集合
#############################################################################
sadd myset "hello" # set集合中添加元素
smembers myset # 查看指定set集合中的所有值
sismember myset hello # 判断某一个值是不是在set集合中
#############################################################################
scard myset # 获取set集合中的元素个数
#############################################################################
srem myset hello # 移除set集合中的指定元素
#############################################################################
set 无序不重复集合。应用场景:抽随机
srandmember myset # 随机抽出一个元素
srandmember myset 2 # 随机抽出指定个数的元素
#############################################################################
# 删除指定的key,随机删除key
spop myset # 随机删除一个set集合中的元素并返回删除的元素
spop myset 2 # 随机删除两个set集合中的元素并返回删除的元素
#############################################################################
# 将一个指定的值,移动到另外一个set集合
smove myset myset2 "member" # 将myset集合中的元素member,移动到myset2集合中
#############################################################################
应用场景:微博,B站,共同关注(并集)
数字集合类:
- 差集 sdiff 返回一个集合与给定集合的差集的元素
- 交集 sinter
- 并集 sunion
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "key2"
127.0.0.1:6379> smembers key1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> smembers key2
1) "c"
2) "e"
3) "d"
127.0.0.1:6379> sdiff key1 key2 # 差集 去掉key1中和key2中相同的元素
1) "b"
2) "a"
127.0.0.1:6379> sdiff key2 key1 # 差集 去掉key2中和key1中相同的元素
1) "e"
2) "d"
127.0.0.1:6379> sinter key1 key2 # 交集
1) "c"
127.0.0.1:6379> sunion key1 key2 # 并集
1) "b"
2) "c"
3) "e"
4) "a"
5) "d"
应用场景:
微博,A用户将所有关注的人放在一个set集合中,将他的粉丝也放在一个集合中。
共同关注,共同爱好,二度好友,推荐好友。(六度分割理论:任何两个素不相识的人,通过一定的方式,总能够产生必然联系或关系)
四、Hash(哈希)
Map集合,key-map,这个值是一个map集合(key-value)。本质和String类型没有太大区别,还是一个简单的key-value。
#############################################################################
hset myhash field lyt # set一个具体的key-value
hget myhash field # 获取一个字段值
hmset myhash field hello field2 world # set多个key-value
hmget myhash field field2 # 获取多个字段值
hgetall myhash # 获取全部的数据 以map集合的形式展示
hdel myhash field # 删除hash指定的key(field)字段,对应的value值也就没了
#############################################################################
# 获取hash的长度 hlen
hlen myhash # 返回有几对键值对
#############################################################################
# 判断某一个key是否存在 hexists
hexists myhash field # 判断hash中指定字段是否存在
#############################################################################
# 只获得所有field字段
hkeys myhash
# 只获得所有value值
hvals myhash
#############################################################################
# 自增incrby 不存在则设置 hsetnx
hincrby myhash field 1 # 每次自增1
hincrby myhash field -1 # 每次自减1
hsetnx myhash field1 hello # 如果不存在则可以设置
hsetnx myhash field1 lyt # 如果存在则不能设置
应用场景:
变更的数据(用户的信息保存,经常变动的信息)user:1 name
hash更适合对象的存储,String更加适合字符串的存储
五、Zset(有序集合)
在set的基础上,增加了一个值,set k1 v1,zset k1 score1 v1
#############################################################################
zadd myzset 1 one # 添加一个值
zadd myszet 2 two 3 three # 添加多个值
zrange myzset 0 -1 # 查看zset中的值
#############################################################################
# 排序如何实现
127.0.0.1:6379> zadd salary 2500 xh # 添加三个用户
(integer) 1
127.0.0.1:6379> zadd salary 5000 zs
(integer) 1
127.0.0.1:6379> zadd salary 500 lyt
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf # 显示全部的用户 按成绩从小到大排序
1) "lyt"
2) "xh"
3) "zs"
127.0.0.1:6379> zrevrange salary 0 -1 # 从大到小进行排序
1) "zs"
2) "lyt"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 显示全部的用户并且附带成绩 -inf负无穷大 +inf正无穷大
1) "lyt"
2) "500"
3) "xh"
4) "2500"
5) "zs"
6) "5000"
#############################################################################
# 移除zset中的元素 zrem
127.0.0.1:6379> zrange salary 0 -1
1) "lyt"
2) "xh"
3) "zs"
127.0.0.1:6379> zrem salary xh # 移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "lyt"
2) "zs"
127.0.0.1:6379> zcard salary # 获取有序集合中的元素个数
(integer) 2
#############################################################################
127.0.0.1:6379> zadd myzset 1 hello 2 world 3 lyt
(integer) 3
127.0.0.1:6379> zrange myzset 0 -1
1) "hello"
2) "world"
3) "lyt"
127.0.0.1:6379> zcount myzset 1 3 # 获取指定区间的成员数量
(integer) 3
127.0.0.1:6379> zcount myzset 1 2
(integer) 2
剩下的API,可以在官网中查看
使用场景:set的排序版
存储班级成绩表,工资表排序,普通消息,1,重要消息,2,带权重进行判断。
排行榜应用实现,取Top N测试。
少年易老学难成,一寸光阴不可轻