redis常用命令和内部编码
文章目录
- redis 为什么快
- redis中的String
- set
- setnx
- setex
- get
- mset
- mget
- 计数操作incr、incrby、decr、decrby、incrbyfloat
- incr
- incrby
- incrbyfloat
- 拼接(append)、获取(getrange)、修改字符串(setrange)、获取字符串长度(strlen)操作
- append
- getrange
- setrange
- strlen
- String编码方式
- 查看String类型(object endoding key)
- String类型的应用场景
- 缓存(cache)
- 计数(counter)
- 共享会话(session)
- 手机验证码
- 哈希Hash
- hset
- hget
- hexists
- hdel
- hkeys
- hvals
- hgetall
- hmget
- hlen
- hsetnx
- hincrby
- hincrbyfloat
- hash类型编码方式
- hash的应用场景
- 缓存(cache)
- 列表(list)
- list特点
- lpush(头插)
- lrange(查看list元素)
- lpushx
- rpush(尾插)
- rpushx
- lpop(头删)
- rpop(尾删)
- lindex
- linsert
- llen
- lrem
- ltrim
- lset
- 阻塞版本命令(消息队列)
- blpop & brpop
- blpop
- brpop
- list内部编码
- list的应用场景
- 作为数组
- 作为消息队列
- 栈或者队列
- 集合(set)
- sadd
- smembers
- sismember
- spop
- smove
- srem
- 集合间操作
- 交集(inter)、并集(union)、差集(diff)
- sinter
- sinterstore
- sunion
- sunionstore
- sdiff
- sdiffstore
- 集合的内部编码
- set的应用场景
- 保存用户的标签
- 使用set计算出用户之间的共同好友
- 使用set统计UV
- 有序集合(zset)
- zadd
- zrange
- zcard
- zcount
- zrevrange
- zrangebyscore
- zpopmax
- zpopmin
- bzpopmax
- bzpopmin
- zrank
- zrevrank
- zscore
- zrem
- zremrangebyrank
- zremrangebyscore
- zincreby
- 集合间操作
- 交集(zinterstore)、并集(zunionstore)
- zinterstore
- zunionstore
- 内部编码
- 应用场景
- 排行榜系统
- 其他数据类型
- Streams
- Geospatial
- HyperLogLog
- Bitmaps
- Bitfields
- 渐进式遍历
- scan
- 数据库管理
redis 为什么快
参照物:数据库(mysql、oracle、sql server)等
1.redis 主要是访问内存,数据库主要是访问硬盘
2.redis 的核心功能比数据库的核心功能更简单(干的活比数据库要少很多)
例如数据库对数据的插入删除都有更复杂的功能支持,例如主键约束等
3.reids 采取的单线程模型,避免了一些不必要的线程竞争开销(例如加锁)
因为redis每个基本操作都是短平快的简单操作一些内存
4.redis 在处理网络IO的时候,使用了epoll的IO多路复用机制(事件通知/回调机制)
IO多路复用:一个线程就可以管理多个socket(操作系统给程序员提供的一套API,
Java中可以使用NIO(底层封装的就是epoll)),当多件事情都是交互不是特别频繁的时候
,可以采用IO多路复用
redis中的String
reids所有的可以都是字符串,value类型是存在差异的
redis中的字符串直接就是按照二进制数据的方式存储的(不会做任何编码的转换,
存的是啥取出来就是啥,所以什么都可以存储)但是有大小限制,最大是512M,
但是不建议存储太大的数据,因为redis是单线程模型,希望每次的操作都是短平快的
set
set key value ex(秒)/px(毫秒) 10 (~原子性操作~)
相当于
set key value
expire key 10(过期时间)
setnx
setnx key1 111
相当于
set key1 111 nx
setex
setex key1 10 222
相当于
set key1 222 ex 10
get
对于get
来说只是支持字符串类型的value
get key
mset
一次可以操作多组键值对可以只通过一次网络通信操作多个键值对
mset key1 111 key2 222 key3 333 ......
mget
一次可以操作多组键值对
mget key1 key2 key3 ......
计数操作incr、incrby、decr、decrby、incrbyfloat
incr 针对value+1
incrby 针对value+n
decr 针对value-1
decrby 针对value-n
incrbyfloat 针对value+/-小数
incr
incr key(key对应的value必须是正数,否则报错,返回的值就是key的value+1的结果)
注意:incr操作的key如果不存在,就会把不存在的结果当成0之后+1返回的是1
incrby
incrby key 10(key对应的value+10并返回)
incrbyfloat
incrbyfloat key 0.5/-0.5(key对应的value+-小数运算)
拼接(append)、获取(getrange)、修改字符串(setrange)、获取字符串长度(strlen)操作
append
append key value(直接将value拼接到key的value后面,
如果key不存在则创建新的key存储)
getrange
类似于Java中subString
getrange key start end(~左闭右闭~)
注意:start end 是可以传递负数的
如果value中保存的是中文,使用getrange得到的结果
可能是会乱码的因为一个汉字代表2-3个字节
setrange
setrange key offset value
offset:偏移量(从第几个字节开始替换)
value:要替换的结果(替换多长,看value的长度)
返回值是替换之后新的字符串长度
注意:如果value中保存的是中文,使用setrange得到的结果可能
是会乱码的因为一个汉字代表2-3个字节
strlen
获取字符串的长度
单位:字节(Byte)
Java中的字符串是以字符为单位的,一个char是两个字节
(Java中汉字编码是用的unicode编码一个汉字使用两个字节,
但是String用的是utf-8一个汉字是三个字节)
strlen key
返回string的长度
String编码方式
int: 8个字节的长整型
embstr: 小于等于39字节的字符串
raw: 大于39个字节的字符串
redis会根据当前值的类型和长度动态决定内部的编码方式
注意:redis存储小数默认是embstr类型
查看String类型(object endoding key)
objeckt endoding key
String类型的应用场景
缓存(cache)
redis缓存只存放热点数据,应用服务器访问数据库的时候,先访问redis缓存,如果有就不会访问数据库,如果没有就访问数据库中的数据,并把数据库中的此数据调用到redis缓存中,以便下次使用,并且会给此数据设置一个过期时间,如果时间到了就销毁,这样redis数据就不会太多,并且redis也提供了淘汰策略
计数(counter)
例如视频的播放量,如果是一个热点视频,频繁的修改数据库中的播放量是效率很慢的,所以可以使用redis作为一个计数器,使用incr计数操作这样效率就会快很多
共享会话(session)
cookie:浏览器存储数据的机制
session(会话) :服务器存储数据的机制
使用redis单独把session会话拎出来,为所有的服务器共享
手机验证码
重点是使用了redis的过期机制
哈希Hash
哈希表是数据结构中最重要的一个数据结构(业务中常涉及到、面试中常问道)
redis
本身已经是键值对结构了,redis
自身的键值对就是通过哈希的方式来组织的,把key这一层组织完之后,到了value这一层value的其中一种类型还可以是哈希(value中是一个哈希表)
注意:在value中的哈市表键值对为field-value
,目的是为了区分外层(key-value)和value中内层的两组不同的键值对
hset
设置hash中指定的字段(field)的值(value)
hset key field1 value1 field2 value2 .....
返回值是设置成功的键值对的个数
hget
获取hash类型键值对的值
hget key field
hexists
判断hash中是否有指定的字段
hexists key field
hdel
删除hash中指定的字段
hdel key field1 field2 .....
hkeys
获取hash中所有的field
hkeys key
时间复杂度:O(n) n表示key中键值对的个数(field个数)
注意:如果hash表中有大量的filed-value,可能会导致redis服务器阻塞
hvals
获取hash中所有的value
hvals key
时间复杂度:O(n) n表示key中键值对的个数(field个数)
hgetall
获取hash中所有的field-value
hgetall key
时间复杂度:O(n) n表示key中键值对的个数(field个数)
hmget
一次查询多个field
hmget key field1 field2 ......
hlen
获取hash中键值对个数
hlen key
时间复杂度:O(1) 不需要遍历
hsetnx
类似于setnx,不存在的时候才设置成功
hsetnx key field value
hincrby
hash这里的value也是可以进行加减操作的
hincrby key field 1/-1
hincrbyfloat
hincrbyfloat key field 0.5/-0.5
hash类型编码方式
ziplist : 压缩列表(节省空间)
hashtable:hash表
但是ziplist付出的代价,是进行读写操作的时候,速度是比较慢的,如果是少数元素并不明显,但是当元素个数比较多,就会比较慢了
如果:
1.哈希中的元素个数比较少,使用ziplist表示,元素个数比较多使用hashtable来表示
2.每个value的值长度都比较短,使用ziplist表示,如果某个value的长度太长了,也会转换成hashtable
hash的应用场景
缓存(cache)
存储一些结构化的数据
列表(list)
相当于数组或者顺序表
list特点
1.列表中的元素是有序的
2.要区分获取和删除的区别(因为删除操作会返回被删除元素的值)
3.列表中的元素是允许重复的
4.因为当前的list头和尾都能高效的插入和删除元素,就可以把这个list当作一个栈/队列来使用
lpush(头插)
lpush key value1 value2 ......
返回值:list的长度
时间复杂度:O(1)
lrange(查看list元素)
lrange key start stop
区间:闭区间
支持负数下标
lpushx
如果key存在时,将一个或多个元素头插到list中,不存在什么也不做
lpushx key value1 value2 .......
返回值:list的长度
rpush(尾插)
rpush key value1 value2 ......
rpushx
如果key存在时,将一个或多个元素尾插到list中,不存在什么也不做
rpushx key value1 value2 ......
返回值:list的长度
lpop(头删)
lpop key
返回值:删除的value值
rpop(尾删)
rpop key
返回值:删除的value值
lindex
给定下标获取对应的元素
lindex key index
时间复杂度 :O(N) N指的是list中元素的个数
如果是非法下标,返回的是nil
下标可以是负数
linsert
linsert key before/after pivot value
在pivot的前面(before)/后面(after)插入value
注意:如果有相同的pivot他会从左往右找到第一个pivot的前/后进行插入
时间复杂度 :O(N) N指的是list中元素的个数
llen
获取列表中的长度
llen key
lrem
删除列表中的元素
lrem key count value
count : 要删除的个数(正数,代表从左往右找,负数,代表从右往左找,零,代表删除所有符合的元素)
value : 要删除的元素
返回:删除的元素的个数
ltrim
保留start和stop之间区间内的元素,区间外的两边元素直接删除
ltrim key start stop
lset
根据下标修改元素
lset key index value
阻塞版本命令(消息队列)
blpop & brpop
如果list中存在元素,blpop和brpop就和lpop和rpop作用完全相同
如果list中不存在元素,blpop和brpop就会阻塞,一直阻塞到队列不为空为止
阻塞版本会根据timeout阻塞一段时间,所以说是可以设置阻塞时间的(不一定是无休止的等待!)
但是在阻塞期间redis可以使用其他命令
此处的blpop和brpop看起来耗时很久,但是实际上并不会对redis服务器造成很大的影响,因为redis还是可以在阻塞期间实行其他命令的
blpop和brpop是可以尝试获取多个列表的,从左往右依次访问,
如果访问到某个匹配的元素之后,就会直接弹出元素,命令返回
如果多个客户端同时对同一个key执行pop,则是最先执行命令的客户端会得到弹出的元素
blpop
blpop key1 key2 ... timeout
可以指定一个key或者多个key,每个key对应的是一个list
如果这些list有任何一个非空,blpop都能够把这里的元素给获取到,立即返回
如果这些list都为空,就需要阻塞等待,等待其他客户端往这些list中插入元素
此处还可以指定超时时间timeout(单位秒),如果过了超时时间阻塞自动解除,返回nil
brpop
brpop和blpop完全一样,只不过brpop是尾删
list内部编码
老版本:
ziplist(元素个数少)
linkedlist(元素个数多)
redis5及之后:
quicklist:结合了ziplist和linkedlist。整体还是一个链表,但是链表的每个节点是一个压缩列表
list的应用场景
作为数组
例如:用来当作不同表之间的关联关系,因为一个list中可以包含多个值
作为消息队列
栈或者队列
集合(set)
1.集合中的元素是无序的
2.集合中的元素是不能重复的,唯一的
3.和list类似,集合中的每一个数据都是string
sadd
为了区分,我们把集合中的每元素叫做member
sadd key member1 member2......
smembers
获取set中所有元素,顺序是无序的
smembers key
sismember
判断元素是否存在
sismenber key member
spop
随机删除
spop key count
count: 随即删除几个(可写可不写,不写只删除一个)
smove
把member从source上删除,再插入到destination中
smove source destination member
srem
删除若干元素
srem key member1 member2 ......
集合间操作
交集(inter)、并集(union)、差集(diff)
sinter
sinter key1 key2 ......
写多少个集合就是对多少个集合求交集
时间复杂度:O(N*M) N是最小集合个数 M是最大集合个数
sinterstore
直接把算好的交集,放到destination这个key对应的集合中
sinterstore destination key1 key2......
sunion
sunion key1 key2 ......
时间复杂度:O(N) N指的是总的元素个数
sunionstore
直接把算好的并集,放到destination这个key对应的集合中
sunionstore destination key1 key2 ......
sdiff
求差集
sdiff key1 key2 ......
时间复杂度:O(N) N指的是总的元素个数
sdiffstore
直接把算好的差集,放到destination这个key对应的集合中
sdiffstore destination key1 key2 ......
集合的内部编码
intset(整数集合) :为了节省空间做出的优化,当元素均为整数,并且元素个数并不是很多的时候
hashtable(哈希表) : 只要是存有字符类型,或者元素个数比较多
set的应用场景
保存用户的标签
用户画像:
分析出一个用户的特性(标签)之后,再投其所好~
使用set计算出用户之间的共同好友
基于“集合求交集”
使用set统计UV
UV:一个互联网产品如何衡量用户量?主要是两个方面PV、UV
1.PV (page view): 用户每次访问都会产生一个PV
2.UV (user view): 每个用户访问服务器都会产生一个UV,但是同一个用户多次访问,不会产生新的UV
UV统计需要去重,可以通过set集合来实现
有序集合(zset)
有序 : 升序
分数(score):再zset中每一个member同时引入了要给属性,叫做分数
(浮点类型),进行排序的时候,就会按照分数的大小进行升序排列
注意:zset中的member仍然要求是唯一的,但是分数(score)可以重复
zadd
添加元素和分数
zset key [NX | XX] [LT | GT] [CH] [INCR] score1 member1 score2 member2 ......
LT : 如果更新的分数比原来的值小就更新,否则不更新
GT : 如果更新的分数比原来的值大就更新,否则不更新
CH : 如果不加ch默认返回的是新增元素的个数,如果加了就会返回修改的元素
INCR : 可以对现有的分数进行运算
时间复杂度 : O(logN) N指的是有序集合中的元素的个数,每次添加都是logN
zrange
查看有序集合 类似于 lrange
zrange key start stop [withscores]
时间复杂度 :O(logN + M) logN找到start和stop下标,M遍历之间的元素
zcard
获取集合中的元素个数
zcard key
zcount
给分数定区间筛选符合元素的个数
zcount key min max
min和max是可以写成浮点数的(inf无穷大,-inf负无穷大)
默认是闭区间,如果设置开区间使用左小括号`(`
时间复杂度 : O(logN)
zrevrange
逆序遍历(降序遍历)
zrevrange key start stop [withscores]
时间复杂度 :O(logN + M) logN找到start和stop下标,M遍历之间的元素
zrangebyscore
按照分数区间查询
zrangebyscore key min max [withscores]
默认是闭区间,如果要使用开区间,就在前面加上左括号`(`
时间复杂度 : O(logN + M)
zpopmax
删除并返回分数最高的count个元素
zpopmax key [count]
如果不写count默认删除一个最大的元素
返回值是被删除的元素
如果存在多个元素分数相同,会删除其中的一个
时间复杂度 : O(log(N) * M) N是有序集合的个数 M是count要删除的元素的个数
zpopmin
删除并返回分数最低的count个元素
zpopmin key [count]
其他的同zpopmax
bzpopmax
带有阻塞的删除分数最高的元素
bzpopmax key1 key2 ...... timeout
每一个key都是一个有序集合 有序集合为空的时候触发阻塞,timeout可以设置阻塞时间
和blpop一样的
时间复杂度 : O(logN)
bzpopmin
带有阻塞的删除分数最低的元素
bzpopmin key1 key2 ...... timeout
其他的同bzpopmax
zrank
返回元素的排名(下标)
zrank key member
时间复杂度 : O(logN)
zrevrank
返回元素的逆序排名(下标)
zrevrank key member
zscore
查询指定元素的分数
zsocre key member
时间复杂度 : O(1)
zrem
删除指定的元素
zrem key member1 member2 ......
时间复杂度 : O(log(N) * M)
zremrangebyrank
按照排序,删除指定范围的元素,左闭右闭
zremrangebyrank key start stop
时间复杂度 : O(logN + M)
zremrangebyscore
按照分数,删除指定范围的元素,左闭右闭
zremrangebyscore key start stop
时间复杂度 : O(logN + M)
zincreby
为指定的元素的分数增/减一定的分数值
zincreby key increment member
集合间操作
交集(zinterstore)、并集(zunionstore)
zinterstore
zinterstore destination numkeys key1 key2 ...... [weights ...][aggregate(sum|max|min)]
weights:权重
aggregate:合计(对相同member的分数进行求和、取最大值、取最小值)默认是sum
zunionstore
zunionstore destination numkeys key1 key2 ...... [weights ...][aggregate(sum|max|min)]
weights:权重
aggregate:合计(对相同member的分数进行求和、取最大值、取最小值)默认是sum![]()
内部编码
ziplist : 如果有序集合元素个数较少,或者单个元素体积较少
skiplist(跳表) : 如果当前元素个数比较多,或者单个元素体积非常大
应用场景
排行榜系统
关键要点:用来排行的分数是实时变化的
其他数据类型
Streams
当事件来了,进行一些操作,相当于一个阻塞队列
属于是List blpop brpop 的升级版
Geospatial
用来存储坐标(经纬度)
存储一些点之后,就可以让用户在某个点的特定范围之内查找周边范围信息
HyperLogLog
估算集合中的元素个数
HyperLogLog能够记录“元素的特征”但是不记录元素的内容,在新增元素的时候,能够知道当前新增的元素是一个已经存在的元素还是一个新的,所以就能记录集合中的元素个数,但是这个始有一定的误差的(误差0.81%)!毕竟“元素的特征”不一定特别准确
Bitmaps
位图
使用bit位来表示整数
位图本质上还是一个集合,属于是Set类型针对整数的特化版本,目的是节省空间
Bitfields
位域(位段)
bitfield可以理解成一串二进制序列(字节数组)
同时可以把这个字节数组中的某几个位,赋予特定的含义,并且可以进行 读取/修改/算术运算 等 相关操作
渐进式遍历
通过渐进式便利,就能做到,既能够获取到所有的key,同时又不会卡死服务器(不同于keys *
)
每次只获取到一部分,保证一次操作不会太卡
scan
scan cursor [MATCH pattern] [COUNT count] [TYPE type]
cursor : 光标位置(开始遍历位置,并不是下标,只要简单理解成一个字符串即可)
count : 遍历的个数,默认是10(不一定精确)
pattern: 匹配字符串规则
type: 指定遍历value类型的key
返回值 : 前半部分告诉你下次遍历,光标是从哪个位置开始,后半部分就是遍历到的key
数据库管理
切换数据库
select dbIndex
deIndex: 0 - 15
查询本库中的key个数
dbsize
删除当前库中所有key
flushdb
删除所有库中所有key
flushall