字符串
字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串如Json、Xml) ,数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB。
命令
(1) 设置值
set key value
set命令有几个选项:
ex seconds: 为键设置秒级过期时间
px milliseconds: 为键设置毫秒级过期时间
nx: 键必须不存在,才可以设置成功,用于添加
xx: 与nx 相反,键必须存在,才可以设置成功,用于更新
set hello world ex 10 nx
setex key seconds value #设置过期时间
setnx key value #键不存在设置key
set key value xx #对存在的键进行更新
(2) 批量设置值
mset key1 value key2 value2 ...
(3) 批量获取值
mget key1 key2 key3 ...
批量get 可以提高开发效率,假如没有mget,要执行n 次get 命令需要的耗时如下:
n次 get 时间= n次网络时间+n次命令时间
使用mget 后执行n次命令耗时如下:
n次 get 时间= 1次网络时间+n次命令时间
(4) 计数
incr key
incr 命令用于对值做自增操作,返回结果分为三种情况:
1)值不是整数,返回错误
2)值是整数,返回自增后的结果
3)键不存在,按照值为0自增,返回结果为1
decr key(自减)
incrby key increment (自增指定数字)
decrby key decrement (自减指定数字)
incrbyfloat key increment (自增浮点数)
(5) 追加值
append key value
127.0.0.1:6379> set sichuan chengdu
OK
127.0.0.1:6379> append sichuan shi
(integer) 10
127.0.0.1:6379> get sichuan
"chengdushi"
(6) 字符串长度
strlen key
每个中文占3个字节
127.0.0.1:6379> set hello "世界"
OK
127.0.0.1:6379> strlen hello
(integer) 6
getset 和set 一样可以设置值,但是返回的是原值
127.0.0.1:6379> getset hello world
(nil)
127.0.0.1:6379> getset hello redis
"world"
(7) 设置指定位置的字符
将下面pest 变成best
127.0.0.1:6379> set redis pest
OK
127.0.0.1:6379> SETRANGE redis 0 b
(integer) 4
127.0.0.1:6379> get redis
"best"
(8) 获取部分字符串
getrange key start end
start end 为偏移量从0开始
内部编码
字符串类型的内部编码有三种:
- int: 8个字节的长整型
- embstr: 小于等于39个字节的字符串
-
raw: 大于39个字节的字符串
redis 会根据当前值得类型和长度决定使用哪种内部编码实现。
哈希
哈希类型是指键值对本身又是一个键值对结构,Redis键值对和哈希类型二者的关系如图:
命令
(1) 设置值
hset key field value
添加一个user
hset user:1 name tom
(2) 获取值
hget key field
hget user:1 name
127.0.0.1:6379> HSET user:1 name tom
(integer) 1
127.0.0.1:6379> hget user:1 name
"tom"
(3) 删除field
hdel 会删除一个或多个field, 结果返回为成功删除的个数
hdel user:1 name
(4) 计算field 的个数
相当于统计对象的属性个数,如user 的age、name…
hlen key
(5) 批量设置或获取field-value
hmset key field value
hmget key field [field]
127.0.0.1:6379> hmset user:1 name tom age 18
OK
127.0.0.1:6379> hmget user:1 name age
1) "tom"
2) "18"
(6) 判断field 是否存在
hexists key field
存在返回1,不存在返回0
(7) 获取所有field
hkeys key
127.0.0.1:6379> hkeys user:1
1) "name"
2) "age"
(8) 获取所有value
hvals key
127.0.0.1:6379> hvals user:1
1) "tom"
2) "18"
(9) 获取所有field和value
hgetall key
127.0.0.1:6379> hgetall user:1
1) "name"
2) "tom"
3) "age"
4) "18"
如果哈希元素比较多,使用hgetall可能会阻塞redis,可以使用hscan,该命令会渐进式遍历哈希类型。
(10) hincrby hincrbyfloat
hincrby key field
hincrbyfloat key field
这两个命令和incrby incrbyfloat 一样只不过作用域是field
(11)
计算value 的字符串长度 (需要redis 3.2以上)
hstrlen key field
内部编码
哈希类型的两种内部编码
-
ziplist(压缩列表)
当创建哈希类型时,如果哈希的field 个数小于512个,同时value小于64字节时 -
hashtable(哈希表)
采用ziplist无法满足时,如果field-value不满足ziplist内部编码条件,则采用hashtable内部编码保存时间复杂度为O(1)
列表
列表(list) 类型是用来存储多个有序的字符串,列表中的每个字符串称为元素,一个列表最大存储2^32-1个元素。在redis中可以从列表两端插入和弹出元素。既可以充当队列又可以当栈。
命令
(1) 添加操作
从右边插入元素。从右至左
rpush key value…value
相当于listkey = [a,b,c]
127.0.0.1:6379> rpush listkey a b c
(integer) 3
(2) 获取所有元素
lrange key 0 -1
127.0.0.1:6379> lrange listkey 0 -1
1) "a"
2) "b"
3) "c"
(3) 从左边插入
lpush key value
和从右边插入结果一样,只不过从左侧插入
127.0.0.1:6379> lpush listkey2 a b c
(integer) 3
127.0.0.1:6379> lrange listkey 0 -1
1) "a"
2) "b"
3) "c"
(4) 插入元素
在某个元素前插入
linsert key before 元素 new元素
如在c++ 前面插入java,返回结果为元素长度
127.0.0.1:6379> lrange dev 0 -1
1) "php"
2) "java"
3) "c"
127.0.0.1:6379> linsert dev before java c++
(integer) 4
127.0.0.1:6379> lrange dev 0 -1
1) "php"
2) "c++"
3) "java"
4) "c"
在某个元素后插入
linsert key after 元素 new元素
(5) 查找
-
获取指定范围内的元素列表
lrange key start end
索引从左至右为0到N-1,但是从右至左为-1到-N
上面已经使用过了,不再举例 -
获取指定索引的元素
lindex key index127.0.0.1:6379> lindex dev 0 "php"
-
获取列表长度
llen key
比如有4个元素127.0.0.1:6379> llen dev (integer) 4
(6) 删除
-
从列表左侧弹出元素
lpop key
“php” 最先弹出
127.0.0.1:6379> lrange dev 0 -1
1) "php"
2) "c++"
3) "java"
4) "c"
127.0.0.1:6379> lpop dev
"php"
127.0.0.1:6379> lrange dev 0 -1
1) "c++"
2) "java"
3) "c"
-
从列表右侧删除
rpop key -
删除指定元素
lrem key count value
根据count 的不同分为三种类型:
count > 0 ,从左至右,删除最多count 个等于value的元素
count < 0 ,从左至右,删除最多|count| 个等于value的元素
count = 0 ,删除所有
比如删除所有”c”127.0.0.1:6379> lrange dev 0 -1 1) "c" 2) "c++" 3) "java" 4) "c" 127.0.0.1:6379> lrem dev 0 "c" (integer) 2
-
按照索引范围修剪列表
ltrim key start end
比如只保留第1个和第2个元素ltrim dev 0 1
(7) 修改
修改指定下标的元素:
lset key index newvalue
比如将第1个元素改为”python”
127.0.0.1:6379> lrange dev 0 -1
1) "c++"
2) "java"
127.0.0.1:6379> lset dev 1 python
OK
127.0.0.1:6379> lrange dev 0 -1
1) "c++"
2) "python"
(8) 阻塞操作
阻塞式弹出如下:
blpop key [key…] value timeout
brpop key [key…] value timeout
-
列表为空:如果timeout=3,那么客户端要等到3秒后返回,如果timeout=0,那么客户端一直阻塞下去,直到有新元素进来pop后返回给客户端以及阻塞时间。
127.0.0.1:6379> brpop list 3 (nil) (3.07s)
先执行brpop dev 0 再添加元素后的结果如下
127.0.0.1:6379> lpush dev php
(integer) 1
127.0.0.1:6379> brpop dev 0
1) "dev"
2) "php"
(30.45s)
-
如果列表不为空,客户端立即返回并弹出一个元素
127.0.0.1:6379> brpop dev 0 1) "dev" 2) "python" 127.0.0.1:6379> lrange dev 0 -1 1) "c++"
注意在使用brpop 时,有两点需要注意:
第一,如果是多个键,那么brpop 会从左至右遍历,一旦有一个键能弹出元素,客户端立即返回。
第二,如果多个客户端对同一个键执行brpop,那么最先执行的brpop 命令的客户端可以获取到弹出的值。
内部编码
列表类型的内部编码有两种。
- ziplist:当列表的值元素个数小于list-max-ziplist-entries(默认是512个),且每个元素的值小于64自己时,redis采用ziplist的形式存储列表,减少了内存的使用。
-
linkedlist:当列表其值不满足ziplist的条件的时候,redis会采用链表的形式存储值。
但在redis3.2版本之后,当元素大于512个或元素大小超过64个字节,内部编码已从linkedlist变为quicklist。quicklist采用了ziplist的优点和linkedlist的优点,也就是每个节点都是一个ziplist节点之间用双向的指针联系起来,这样即使得内存使用的减少满足了快速的插入和删除,也减少了空间的冗余。
使用场景
lpush+lpop=Stack(栈)
lpush+rpop=Queue(队列)
lpsh+ltrim=Capped Collection(有限集合)
lpush+brpop=Message Queue(消息队列)
集合
集合(set) 类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复的元素,并且集合中的元素是无序,不能通过索引下标获取元素。
命令
(1) 集合内操作
添加元素
sadd key element
127.0.0.1:6379> sadd project c c++ java
(integer) 3
删除元素
srem key element
返回成功删除的个数
127.0.0.1:6379> srem project c++
(integer) 1
计算元素个数
scard key
scard 时间复杂度为O(1),它不会遍历所有元素,二是直接用redis 内部变量
127.0.0.1:6379> scard project
(integer) 2
判断元素是否在集合中
sismember key element
存在返回1。反之为0
127.0.0.1:6379> sismember project java
(integer) 1
随机从集合中返回指定元素个数
srandmember key count
127.0.0.1:6379> srandmember project 2
1) "c"
2) "java"
从集合中随机弹出元素
spop key
127.0.0.1:6379> spop project
"c"
c 已经从集合中删除
获取所有元素
smembers key
127.0.0.1:6379> smembers project
1) "java"
(2) 集合间操作
求多个集合的交集
sinter key key
127.0.0.1:6379> sadd project c++ php
(integer) 2
127.0.0.1:6379> sadd project2 c++ java python net
(integer) 4
127.0.0.1:6379> sinter project project2
1) "c++"
2) "java"
求多个集合的并集
sunion key key
127.0.0.1:6379> sunion project project2
1) "python"
2) "c++"
3) "php"
4) "java"
5) "net"
求多个集合的差集
sdiff key key
127.0.0.1:6379> sdiff project project2
1) "php"
127.0.0.1:6379> sdiff project2 project
1) "python"
2) "net"
将交集、并集、差集的结果保存
sinterstore destination key key
sunionstore destination key key
sdiffstore destination key key
127.0.0.1:6379> smembers project2
1) "c"
2) "php"
3) "net"
127.0.0.1:6379> smembers project
1) "python"
2) "c++"
3) "java"
4) "net"
127.0.0.1:6379> sinterstore store project project2
(integer) 1
127.0.0.1:6379> smembers store
1) "net"
store 本身也是一个集合
内部编码
集合(set)类型的两种内部编码
- intset(整数集合)
- 当创建集合类型时,如果集合的元素个数小于512个,且元素都为整数是内部编码为intset
-
hashtable(哈希表)
采用intset为内部编码保存,如果元素和元素值不满足intset内部编码条件,则采用hashtable内部编码保存
使用场景
集合类型比较典型的使用场景是标签(tag),例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣就是标签。
有序集合
有序集合保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。和列表下标不一样的是,它是给每个元素设置一个分数(score) 作为排序的依据。
命令
(1) 集合内
添加成员
zadd key score member [score member…]
127.0.0.1:6379> zadd user 150 tom
(integer) 1
Redis3.2 为zadd 命令添加了nx,xx,ch,incr 四个选项:
nx: member 必须不存在,才可以设置成功,用于添加
xx: member 必须存在,才可以设置成功,用于更新
ch: 返回此次操作后,有序集合元素和分数发生变化的个数
incr: 对score 做增加,相当于后面介绍的zincrby
有序集合相比集合增加了排序字段,但是也产生了代价,zadd 的时间复杂度为O(log(n)),sadd 的时间复杂度为O(1)
计算成员个数
zcard key
计算某个成员的分数
zsocre key member
127.0.0.1:6379> zscore user tom
"150"
计算成员排名
zrank key member
zrevrank key member
zrank 是从分数从低到高返回排名,zrevrank 反之。排名从0开始
127.0.0.1:6379> zrank user tom
(integer) 1
127.0.0.1:6379> zrank user jack
(integer) 0
删除成员
zrem key member
127.0.0.1:6379> zrem user tom
(integer) 1
增加成员的分数
zincrby key increment member
jack 增加10分
127.0.0.1:6379> zincrby user 10 jack
"130"
返回指定排名范围内的成员
zrange key start end [withscores]
127.0.0.1:6379> zrange user 0 2 withscores
1) "rank"
2) "80"
3) "tom"
4) "100"
5) "jack"
6) "130"
zrange 是从低到高返回,zrevrange 反之,如果加上withscores 参数则连分数一起返回。
返回指定分数范围内的成员
zrangevyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
127.0.0.1:6379> zrangebyscore user 100 150
1) "tom"
2) "jack"
min 和max 还支持开区间()和闭区间[], -inf 和+inf 分别代表无限小和无限大。
返回指定分数范围内的个数
zcount key min max
127.0.0.1:6379> zcount user 120 200
(integer) 1
删除指定排名内的升序元素
zremrangebyrank key start end
删除指定分数范围内的成员
zremrangebyscore key min max
(2) 集合间操作
交集
zinterstore destination numkeys key … [weights weight…] [aggregate sum|min|max]
这个命令参数较多,下面分别进行说明
destination: 交集计算结果保存到这个键
numkeys:需要做交集计算键的个数
key[key…]: 需要做交集计算的键
weights weight[weight…] :每个键的权重,在做交集计算时,每个键中的的每个member 会将自己分数乘以这个权重,每个键的权重默认是1。
aggregate sum|min|max: 计算成员交集后,分值可以按照sum、min、max 做汇总,默认值是sum
sum:取交集后值相加
max:取交集后保留值最大的
127.0.0.1:6379> zinterstore store2 2 user user2 weights 1 0.5 aggregate max
(integer) 2
127.0.0.1:6379> zrange store2 0 -1 withscores
1) "tom"
2) "100"
3) "jack"
4) "130"
并集
zunionstore destination numkeys key … [weights weight…][aggregate sum|min|max]
内部编码
有序集合类型的内部编码有两种
- ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value 配置(64字节)时,redis 会使用ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。
- skiplist(跳跃表):当ziplist 条件不满足时,有序集合会使用skiplist 作为内部实现,因为此时ziplist 的读写效率会下降。
使用场景
有序集合比较典型的使用场景就是排行榜系统。例如视频网站的播放量排行,榜单的维度可能是时间、播放量、点赞。