Redis的使用(初阶)
一、Redis的使用
1.1、Redis的安装
Ubuntu版本安装:
首先切换到 root 账号,输入下面命令后输入密码即可切换到 root 账号,如果已经是 root 用户就不用操作了。
su root
然后输入下面命令安装 Redis。
apt install redis
其实上面两步就已经安装完Redis了,但是Redis默认绑定的IP是127.0.0.1(本地环回),只允许当前主机客户端访问,不允许其他主机访问,所以还需要进行一些配置。查看绑定IP命令如下:
netstat -nap | grep redis
更改配置:首先进入 Redis 所在目录,使用如下命令:
cd /etc/redis
然后打开配置文件:
vim redis.conf
找到IP,将IP更改为0.0.0.0:
配置文件原始IP:
修改后:
将当前保护模式取消:
取消前:
取消后:
更改配置后,重新启动服务区,使用如下命令:
service redis-server restart
检查是否重启成功(输入命令后,显示图片中绿色的 running 就是成功了):
service redis-server status
此时检查 IP 也变为了0.0.0.0
测试连接:
先输入 redis-cli 进行连接,然后输入 ping 命令进行测试。ping命令返回如下图红框所示即为连接成功。
测试结束后输入 Ctrl + d 断开连接。
1.2、通用命令
注意:Redis 中命令不区分大小写。Redis 是键值对结构,key 固定就是字符串,value 有多种类型。
set 命令:
set key值 value值
key,value不需要加引号,默认会被当做字符串类型,也可以加上引号,单引号和双引号都可以。
get 命令:
get key值
get 命令输入 key 就能得到对应的 value,当 key 不存在时返回 nil。
keys 命令:
keys pattern
keys 命令能够返回所有符合样式的 key。pattern 表示要匹配的模式,即要匹配什么样的 key。
pattern 支持的样式:
- h?llo ?表示匹配一个任意字符。 例如,匹配 hello , hallo 和 hxllo
- h*llo * 表示匹配 0个 或 任意 多个字符。 例如,匹配 hllo 和 heeeello
- h[ae]llo [ ] 表示只能匹配 [ ] 中的字符,相当于给出固定选项了。例如,匹配 hello 和 hallo 但不匹配 hillo
- h[^e]llo [^字符] 表示排除该字符,除了该字符不能匹配,其他都可以。例如,匹配 hallo , hbllo , ... 但不匹配 hello
- h[a-b]llo [字符 - 字符] 表示匹配这个范围内的字符,包含两侧边界。例如:匹配 hallo 和 hbllo
注意:keys 命令的时间复杂度是O(n),所以在生产环境上一般会禁止使用 keys 命令。
exists 命令:
EXISTS key [key ...]
判断某个 key 是否存在。返回值:key 存在的个数。
del 命令:
DEL key [key ...]
删除指定的 key。返回值:删除掉的 key 的个数。
expire 命令:
EXPIRE key seconds
为指定的 key 添加秒级的过期时间,这个 key 必须存在,否则会设置失败。返回值:1 表⽰设置成功。0 表⽰设置失败。
ttl 命令:
TTL key
获取指定 key 的过期时间,秒级。返回值:剩余过期时间。-1 表⽰没有关联过期时间,-2 表⽰ key 不存在。
注意:EXPIRE 和 TTL 命令都有对应的⽀持毫秒为单位的版本:PEXPIRE 和 PTTL。
type 命令:
TYPE key
返回 key 对应的 value 的数据类型。返回值: none , string , list , set , zset , hash and stream 。
1.3、string 类型
注意:
- Redis 内部存储字符串完全是按照⼆进制流的形式保存的,所以 Redis 是不处理字符集编码问题的,客⼾端传⼊的命令中使⽤的是什么字符集编码,就存储什么字符集编码。
- 字符串类型的值实际可以是字符串,包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;数字,可以是整型或者浮点型;甚⾄是⼆进制流数据,例如图⽚、⾳频、视频等。不过⼀个字符串的最⼤值不能超过 512 MB。
1.3.1、常见命令
SET 命令:
SET key value [ EX seconds | PX milliseconds ] [NX | XX]
使用 SET 命令设置 string 类型的 value 时。如果 key 之前存在,则覆盖,⽆论原来的数据类型是什么。之前关于此 key 的 TTL 也全部失效。
SET 命令⽀持多种选项来影响它的⾏为:
- EX seconds:使⽤秒作为单位设置 key 的过期时间。
- PX milliseconds:使⽤毫秒作为单位设置 key 的过期时间。
- EX 和 PX 选项在一条命令中只能使用一个。
- NX :只在 key 不存在时才进⾏设置,即如果 key 之前已经存在,设置不执⾏。
- XX :只在 key 存在时才进⾏设置,即如果 key 之前不存在,设置不执⾏。
- NX 和 XX 选项在一条命令中只能使用一个。
注意:由于带选项的 SET 命令可以被 SETNX 、 SETEX 、 PSETEX 等命令代替,所以之后的版本中,Redis 可能进⾏合并。
返回值:
- 如果设置成功,返回 OK。
- 如果由于 SET 指定了 NX 或者 XX 但条件不满⾜,SET 不会执⾏,并返回(nil)。
FLUSHALL 命令:
FLUSHALL
把 Redis 上所有的键值对全部清除。
GET 命令:
GET key
获取 key 对应的 value。如果 key 不存在,返回 nil。如果 value 的数据类型不是 string,会报错。
返回值:key 对应的 value,或者 nil 当 key 不存在。
MGET 命令:
MGET key [key ...]
⼀次性获取多个 key 的值。如果对应的 key 不存在或者对应的数据类型不是 string,返回 nil。
MSET 命令:
MSET key value [key value ...]
⼀次性设置多个 key 的值。返回值:永远是 OK。
SETNX 命令:
SETNX key value
设置 key-value 但只允许在 key 之前不存在的情况下。
返回值:1 表⽰设置成功。0 表⽰没有设置。
SETEX / PSETEX 命令:
SETEX / PSETEX key value 时间
上述两个命令都是设置 key 的过期时间,其中 SETEX 单位是秒,PSETEX 单位是毫秒。
1.3.2、计数命令
INCR 命令:
INCR key
将 key 对应的 string 表⽰的数字加⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
返回值:integer 类型的 value 加完 1 后的数值。
INCRBY 命令:
INCRBY key decrement(即想要加的数)
将 key 对应的 string 表⽰的数字加上对应的值,这个值可以是正数也可以是负数。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
返回值:integer 类型的 value 加完对应的值后的数值。
DECR 命令:
DECR key
将 key 对应的 string 表⽰的数字减⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
返回值:integer 类型的 value 减完 1 后的数值。
DECYBY 命令:
DECRBY key decrement decrement表示需要减去的数字
将 key 对应的 string 表⽰的数字减去对应的值,这个值可以是正数也可以是负数。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
返回值:integer 类型的 value 减完对应的值后的数值。
INCRBYFLOAT 命令:
INCRBYFLOAT key increment increment表示要加的数
将 key 对应的 string 表⽰的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的不是 string,或者不是⼀个浮点数,则报错。允许采⽤科学计数法表⽰浮点数。
返回值:加/减完后的数值。
1.3.3、其他命令
APPEND 命令:
APPEND KEY VALUE
如果 key 已经存在并且是⼀个 string,命令会将 value 追加到原有 string 的后边。如果 key 不存在, 则效果等同于 SET 命令。
返回值:追加完成之后 string 的⻓度,长度的单位是字节。
注意:在启动Redis客户端的时候,加上一个 --raw 选项,可以使Redis客户端自动尝试对二进制数据进行翻译。
GETRANGE 命令:
GETRANGE key start end
返回 key 对应的 string 的⼦串,由 start 和 end 确定(左闭右闭)。可以使⽤负数表⽰倒数。-1 代表倒数第⼀个字符,-2 代表倒数第⼆个,其他的与此类似。超过范围的偏移量会根据 string 的⻓度调整成正确的值。
返回值:string 类型的⼦串
SETRANGE 命令:
SETRANGE key offset value
覆盖字符串的⼀部分,从指定的偏移处开始。offset 表示相对于起始位置的偏移量。该命令对于不存在的 key 也是可以操作的,只不过会把 offset 之前的内容填充成 0x00。
返回值:替换后的 string 的⻓度,长度的单位是字节。
STRLEN 命令:
STRLEN key
获取 key 对应的 string 的⻓度。当 key 存放的类似不是 string 时,报错。
返回值:string 的⻓度,单位是字节。或者当 key 不存在时,返回 0。
1.4、hash 类型
哈希类型中的映射关系通常称为 field-value,⽤于区分 Redis 整体的键值对(key-value), 注意这⾥的 value 是指 field 对应的值,不是键(key)对应的值。
1.4.1、常见命令
HSET 命令:
HSET key field value [field value ...]
设置 hash 中指定的字段(field)的值(value)。
返回值:添加的字段的个数。
HGET 命令:
HGET key field
获取 hash 中指定字段的值。
返回值:字段对应的值或者 nil。
HEXISTS 命令:
HEXISTS key field
判断 hash 中是否有指定的字段。
返回值:1 表⽰存在,0 表⽰不存在。
HDEL 命令:
HDEL key field [field ...]
删除 hash 中指定的字段。
返回值:本次操作删除的字段个数。
HKEYS 命令:
HKEYS key
获取 hash 中的所有字段。
返回值:字段列表。
HVALS 命令:
HVALS key
获取 hash 中的所有的值。
返回值:所有的值。
HGETALL 命令:
HGETALL key
获取 hash 中的所有字段以及对应的值。
返回值:字段和对应的值。
HMGET 命令:
HMGET key field [field ...]
⼀次获取 hash 中多个字段的值。
返回值:字段对应的值或者 nil。
HLEN 命令:
HLEN key
获取 hash 中的所有字段的个数。
返回值:字段个数。
HSETNX 命令:
HSETNX key field value
在字段不存在的情况下,设置 hash 中的字段和值。
返回值:1 表⽰设置成功,0 表⽰失败。
HINCRBY 命令:
HINCRBY key field increment
将 hash 中字段对应的数值添加指定的值。hash 中通过这一个命令实现整数的加减,因为 increment 既可以传正数也可以传负数。
返回值:该字段变化之后的值。
HINCRBYFLOAT 命令:
HINCRBYFLOAT key field increment
HINCRBY 的浮点数版本。
返回值:该字段变化之后的值。
1.5、list 类型
列表相当于数组,但是它的编码方式并不是一个简单的数组,而是类似于C++中的双端队列,它具有以下特点:
- 第⼀、列表中的元素是有序的,这意味着可以通过索引下标获取某个元素或者某个范围的元素列表。
- 第⼆、区分获取和删除的区别,获取某个列表元素时不会将该元素从列表中删除。
- 第三、列表中的元素是允许重复的。
1.5.1、常见命令
LPUSH 命令:
LPUSH key element [element ...]
将⼀个或者多个元素从左侧放⼊(头插)到 list 中。如果 key 已经存在且 value 类型不是 list,该命令就会报错。
返回值:插⼊后 list 的⻓度。
LRANGE 命令:
LRANGE key start stop
查看 list 中指定范围内的元素,此处的区间也是闭区间,下标支持负数(例如 -1 代表倒数第一个元素)。
LPUSHX 命令:
LPUSHX key element [element ...]
在 key 存在时,将⼀个或者多个元素从左侧放⼊(头插)到 list 中。不存在,直接返回。
返回值:插⼊后 list 的⻓度。
RPUSH 命令:
RPUSH key element [element ...]
将⼀个或者多个元素从右侧放⼊(尾插)到 list 中。
返回值:插⼊后 list 的⻓度。
RPUSHX 命令:
RPUSHX key element [element ...]
在 key 存在时,将⼀个或者多个元素从右侧放⼊(尾插)到 list 中。
返回值:插⼊后 list 的⻓度。
LPOP 命令:
LPOP key
从 list 左侧取出元素(即头删)。
返回值:被删除的元素或者 nil。
RPOP 命令:
RPOP key
从 list 右侧取出元素(即尾删)。
返回值:被删除的元素或者 nil。
LINDEX 命令:
LINDEX key index
获取从左数第 index 位置的元素。
返回值:取出的元素或者 nil。
LINSERT 命令:
LINSERT key <BEFORE | AFTER> pivot element
在特定位置插⼊元素。BEFORE 和 AFTER 两个选项表示插入到指定位置的前面还是后面, pivot 表示基准值,即要插入到哪个已经存在的元素附近,如果这个基准值存在多个,以从左向右找到的第一个为准,element 表示要插入的值。
返回值:插⼊后的 list ⻓度。
LLEN 命令:
LLEN key
获取 list ⻓度。
LREM 命令:
LREM key count element
该命令可以删除指定个数的指定元素,element 表示要删除的是哪个元素,count 表示删除的个数,当 count > 0 时表示从左向右删除指定个数;当 count < 0 时表示从右向左删除指定个数;当 count = 0 时表示将指定元素全部删除。
LTRIM 命令:
LTRIM key start stop
保留 start 和 stop 区间内的元素,区间外面两边的元素都会被删除。
LSET 命令:
LSET key index element
根据下标(index)修改元素。
BLPOP 命令:
BLPOP key [key ...] timeout
LPOP 的阻塞版本。返回值:取出的元素或者 nil。
BRPOP 命令:
BRPOP key [key ...] timeout
RPOP 的阻塞版本。返回值:取出的元素或者 nil。
blpop 和 brpop 是 lpop 和 rpop 的阻塞版本,和对应⾮阻塞版本的作⽤基本⼀致,除了:
- 在列表中有元素的情况下,阻塞和⾮阻塞表现是⼀致的。但如果列表中没有元素,⾮阻塞版本会理解返回 nil,但阻塞版本会根据 timeout,阻塞⼀段时间,期间 Redis 可以执⾏其他命令,但要求执⾏该命令的客户端会表现为阻塞状态。
- 命令中如果设置了多个键,那么会从左向右进行遍历键,⼀旦有⼀个键对应的列表中可以弹出元素,命令⽴即返回。
- 如果多个客户端同时多⼀个键执⾏ pop,则最先执⾏命令的客户端会得到弹出的元素。
1.6、set 类型
集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中的元素之间是⽆序 的,并且元素不允许重复。⼀个集合中最多可以存储个元素。Redis 除了⽀持集合内的增删查改操作,同时还⽀持多个集合取交集、并集、差集,合理地使⽤好集合类型,能在实际开发中解决很多问题。
1.6.1、普通命令
SADD 命令:
SADD key member [member ...]
将⼀个或者多个元素添加到 set 中。注意,重复的元素⽆法添加到 set 中。
返回值:本次添加成功的元素个数。
SMEMBERS 命令:
SMEMBERS key
获取⼀个 set 中的所有元素,注意,元素间的顺序是⽆序的。
SISMEMBER 命令:
SISMEMBER key member
判断⼀个元素在不在 set 中。
返回值:1 表⽰元素在 set 中。0 表⽰元素不在 set 中或者 key 不存在。
SCARD 命令:
SCARD key
获取⼀个 set 的基数(cardinality),即 set 中的元素个数。
返回值:set 内的元素个数。
SPOP 命令:
SPOP key [count]
从 set 中删除并返回⼀个或者多个元素。注意,由于 set 内的元素是⽆序的,所以取出哪个元素实际是未定义⾏为,即可以看作随机的。
返回值:取出的元素。
SMOVE 命令:
SMOVE source destination member
将⼀个元素从源 set 取出并放⼊⽬标 set 中。
返回值:1 表⽰移动成功,0 表⽰失败。
SREM 命令:
SREM key member [member ...]
将指定的元素从 set 中删除。
返回值:本次操作删除的元素个数。
1.6.2、集合间操作
SINTER 命令:
SINTER key [key ...]
获取给定 set 的交集中的元素。
返回值:交集的元素。
SINTERSTORE 命令:
SINTERSTORE destination key [key ...]
获取给定 set 的交集中的元素并保存到⽬标 set 中,即放到 destination 这个 key 对应的集合中。
返回值:交集的元素个数。
SUNION 命令:
SUNION key [key ...]
获取给定 set 的并集中的元素。
返回值:并集的元素。
SUNIONSTORE 命令:
SUNIONSTORE destination key [key ...]
获取给定 set 的并集中的元素并保存到⽬标 set 中。
返回值:并集的元素个数。
SDIFF 命令:
SDIFF key [key ...]
获取给定 set 的差集中的元素。
返回值:差集的元素。
SDIFFSTORE 命令:
SDIFFSTORE destination key [key ...]
获取给定 set 的差集中的元素并保存到⽬标 set 中。
返回值:差集的元素个数。
1.7、Zset 有序集合
有序集合相对于字符串、列表、哈希、集合来说会有⼀些陌⽣。它保留了集合不能有重复成员的 特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数(score)与之关联,这使得有序集合中的元素是可以维护有序性的,但这个有序不是⽤下标作为排序依据⽽是⽤这个分数。一个 zset 中不同元素的分数可以相同,当分数相同时,以元素的字典序排列。zset 内部是按照升序来排列的。
1.7.1、普通命令
ZADD 命令:
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]
添加或者更新指定的元素以及关联的分数到 zset 中,分数应该符合 double 类型,+inf/-inf 作为正负极限也是合法的。
ZADD 的相关选项:
- XX:仅仅⽤于更新已经存在的元素,不会添加新元素。
- NX:仅⽤于添加新元素,不会更新已经存在的元素。
- LT:当元素不存在时,直接添加;当元素存在时,只有当前给定的分数比之前小才能添加成功。
- GT:当元素不存在时,直接添加;当元素存在时,只有当前给定的分数比之前大才能添加成功。
- CH:默认情况下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。
- INCR:此时命令类似 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数。
返回值:本次添加成功的元素个数。
ZCARD 命令:
ZCARD key
获取⼀个 zset 的基数(cardinality),即 zset 中的元素个数。
返回值:zset 内的元素个数。
ZCOUNT 命令:
ZCOUNT key min max
返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含的,可以通过 ( 排除。例如排除min值:zcount key (min max;排除 min 和 max:zcount key (min (max。
注意:min 和 max 也可以写做 inf (无穷大) 或者 -inf (负无穷大)。
返回值:满⾜条件的元素列表个数。
ZRANGE 命令:
ZRANGE key start stop [WITHSCORES]
返回指定区间⾥的元素,分数按照升序。带上 WITHSCORES 可以把分数也返回。此处的 [start, stop] 为下标构成的区间。从 0 开始, ⽀持负数。
返回值:区间内的元素列表。
ZREVRANGE 命令:
ZREVRANGE key start stop [WITHSCORES]
返回指定区间⾥的元素,分数按照降序。带上 WITHSCORES 可以把分数也返回。
返回值:区间内的元素列表。
注意:这个命令可能在 6.2.0 之后废弃,并且功能合并到 ZRANGE 中。
ZRANGEBYSCORE 命令:
ZRANGEBYSCORE key min max [WITHSCORES]
返回分数在 min 和 max 之间的元素,默认情况下,min 和 max 都是包含的,可以通过 ( 排除。
返回值:区间内的元素列表。
注意:这个命令可能在 6.2.0 之后废弃,并且功能合并到 ZRANGE 中。
ZPOPMAX 命令:
ZPOPMAX key [count]
删除并返回分数最⾼的 count 个元素。当有多个分数相同且同为最大值,在不指定删除几个的情况下,默认只删除一个(根据字典序删除)。
返回值:分数和元素列表。
BZPOPMAX 命令:
BZPOPMAX key [key ...] timeout
ZPOPMAX 的阻塞版本。传入的阻塞时间单位是秒,支持小数形式。
返回值:元素列表。
ZPOPMIN 命令:
ZPOPMIN key [count]
删除并返回分数最低的 count 个元素。
返回值:分数和元素列表。
BZPOPMIN 命令:
BZPOPMIN key [key ...] timeout
ZPOPMIN 的阻塞版本。
返回值:元素列表。
ZRANK 命令:
ZRANK key member
返回指定元素的排名,升序。
ZREVRANK 命令:
ZREVRANK key member
返回指定元素的排名,降序。
ZSCORE 命令:
ZSCORE key member
返回指定元素的分数。
ZREM 命令:
ZREM key member [member ...]
删除指定的元素。
返回值:本次操作删除的元素个数。
ZREMRANGEBYRANK 命令:
ZREMRANGEBYRANK key start stop
按照排序,升序删除指定范围的元素,左闭右闭。
返回值:本次操作删除的元素个数。
ZREMRANGEBYSCORE 命令:
ZREMRANGEBYSCORE key min max
按照分数删除指定范围的元素,左闭右闭。
返回值:本次操作删除的元素个数。
ZINCRBY 命令:
ZINCRBY key increment member
为指定的元素的关联分数添加指定的分数值。increment 可以是正数,也可以是负数。
返回值:增加后元素的分数。
1.7.2、集合间操作
ZINTERSTORE 命令:(有序集合的交集操作)
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX> ]
求出给定有序集合中元素的交集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数。destination 为若干集合的交集所存放的集合。numkeys 表示有多少 key 参与交集运算。WEIGHTS 选项后面跟着每个集合的权重。AGGREGATE 选项后面跟着分数的聚合方式(求和,取最小,取最大)。
返回值:⽬标集合中的元素个数
注意:有序集合求交集时,只考虑 member 是否相同,不管分数。
ZUNIONSTORE 命令:(有序集合的并集操作)
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
求出给定有序集合中元素的并集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数。WEIGHTS 和 AGGREGATE 选项的作用和 ZINTERSTORE 命令中一样。
返回值:⽬标集合中的元素个数
1.8、渐进式遍历
Redis 使⽤ scan 命令进⾏渐进式遍历键,进⽽解决直接使⽤ keys 获取键时可能出现的阻塞问 题。每次 scan 命令的时间复杂度是 O(1),但是要完整地完成所有键的遍历,需要执⾏多次 scan。
SCAN 命令:
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
以渐进式的⽅式进⾏键的遍历。cursor 是一个光标,表示从哪里开始遍历,当 cursor 为 0 时,表示从头开始遍历,cursor 不能理解成下标,它不是一个连续递增的整数。pattern 表示要匹配的模式,即要匹配什么样的 key。
pattern 支持的样式:
- h?llo ?表示匹配一个任意字符。 例如,匹配 hello , hallo 和 hxllo
- h*llo * 表示匹配 0个 或 任意 多个字符。 例如,匹配 hllo 和 heeeello
- h[ae]llo [ ] 表示只能匹配 [ ] 中的字符,相当于给出固定选项了。例如,匹配 hello 和 hallo 但不匹配 hillo
- h[^e]llo [^字符] 表示排除该字符,除了该字符不能匹配,其他都可以。例如,匹配 hallo , hbllo , ... 但不匹配 hello
- h[a-b]llo [字符 - 字符] 表示匹配这个范围内的字符,包含两侧边界。例如:匹配 hallo 和 hbllo
count 表示这次遍历想要获取的元素个数,但是这对 Redis 只是一个建议,真实返回的元素个数不一定是 count 个。type 用来指定这次遍历获取 value 为哪种类型的 key。
返回值:下⼀次 scan 的游标(cursor)以及本次得到的键。当命令返回的 cursor 回到 0,说明所有符合条件的 key 都已经遍历完了。
除了 scan 以外,Redis ⾯向哈希类型、集合类型、有序集合类型分别提供了 hscan、sscan、zscan 命令,它们的⽤法和 scan 基本类似。
注意:渐进性遍历 scan 虽然解决了阻塞的问题,但如果在遍历期间键有所变化(增加、删除),可能导致遍历时键的重复遍历或者遗漏,这点务必在实际开发中考虑。
1.9、数据库管理
Redis 中也有像 MySQL 那样的 database 的概念,但不能像 MySQL 中那样随意操作,Redis 中的 database 是现成的,用户不能创建新的数据库,也不能删除已有数据库,Redis 默认提供了十六个数据库,分别对应 0~15 号,这十六个数据库中的数据是隔离的,相互之间不会影响。Redis 提供了⼏个⾯向 Redis 数据库的操作,分别是 dbsize、select、flushdb、flushall 命令。
1.9.1、切换数据库
select dbIndex
许多关系型数据库,例如 MySQL ⽀持在⼀个实例下有多个数据库存在的,但是与关系型数据库⽤ 字符来区分不同数据库名不同,Redis 只是⽤数字作为多个数据库的实现。Redis 默认配置中是有16 个数据库。select 0 操作会切换到第⼀个数据库,select 15 会切换到最后⼀个数据库。0 号数据库和 15 号数据库保存的数据是完全不冲突的,即各种有各⾃的键值对。默认情况下,我们处于数据库 0。
1.9.2、获取当前数据库 key 个数
dbsize
返回值:当前所处数据库的 key 的总个数。
1.9.3、清除数据库
删除当前数据库中所有 key:
flushdb
删除所有数据库中所有 key:
flushall
注意:永远不要在线上环境执⾏清除数据的操作!!!
1.10、Redis客户端—C++
下面介绍如何在C++代码中使用Redis。注意:下面介绍的操作都是在Linux环境下。
1.10.1、创建Redis对象
首先要包含 Redis 的头文件(下面这种方式是建立在头文件导入到系统路径的基础之上):
#include<sw/redis++/redis++.h>
创建 Redis 对象:
sw::redis::Redis redis("tcp://127.0.0.0:6379");
创建 Redis 对象必须指定命令空间,形参传入 Redis 服务器的 URL。这里演示的是当客户端和服务器在一台主机上时的写法,如果不在一台主机上,根据实际情况更改 IP 和 port 即可,但是需要注意 IP是可达的,并且端口也是可以访问的。6379 是 Redis 服务器默认的端口。
1.10.2、如何编译
因为我们使用了 redis++ 的库,所以需要指定库文件路径,同时 redis++ 又依赖于 hiredis 库,同时里面还有线程的操作,所以编译命令中这三个库我们都需要指定出来。命令如下:(下面为 makefile 文件中的写法,如果使用命令行将 $@ 和 $^ 替换为实际的文件名即可)
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
1.10.3、通用方法的使用
在C++代码中使用Redis和使用命令行命令很像,只不过这些命令变成了函数,需要通过Redis类的实例化对象进行调用。下面会演示一些常见命令在C++代码中如何使用,其他没有演示到的命令同理。具体每个方法的详细使用可以到下面网站去看:https://github.com/sewenew/redis-plus-plus#https://github.com/sewenew/redis-plus-plus#
get/set命令:
#include<iostream>
#include<sw/redis++/redis++.h>void test1(sw::redis::Redis& redis)
{//先清空一下数据库,防止干扰redis.flushdb();//使用set设置keyredis.set("key1", "111");redis.set("key2", "222");redis.set("key3", "333");//使用get获取valueauto value1 = redis.get("key1");if(value1){std::cout << value1.value() << std::endl;}
}int main()
{sw::redis::Redis redis("tcp://127.0.0.0:6379");test1(redis);return 0;
}
两点需要注意:
- get 方法返回数据的不是 string 类型,而是 sw::redis::OptionalString 类型,直接使用 cout 打印是不支持的,因为没有对应的 << 运算符重载,需要通过返回值的value方法获取内部的字符串来打印。
- 使用 get 方法返回的值时需要先判断一下这个值是否存在,因为一旦传入错误的 key 是获取不到值的,这时用返回值的value方法去获取内部的结果时就会抛异常。
exists:
#include<iostream>
#include<sw/redis++/redis++.h>void test2(sw::redis::Redis& redis)
{redis.flushdb();redis.set("key", "111");auto ret = redis.exists("key");std::cout << ret << std::endl;//同时判定多个auto ret2 = redis.exists({"key", "key2", "key3"});std::cout << ret2 << std::endl;
}int main()
{sw::redis::Redis redis("tcp://127.0.0.0:6379");test2(redis);return 0;
}
exists 方法既可以判断一个 key 是否存在,也可以判断多个,返回值为long long类型,表示 key 存在的个数。
del方法:
void test3(sw::redis::Redis& redis)
{redis.set("key", "111");redis.set("key2", "222");redis.set("key3", "333");//删除一个auto ret = redis.del("key");//删除任意个auto ret2 = redis.del({"key2", "key3"});
}
del 方法既可以一次删除一个key,也可以一次删除多个,返回值为long long类型,表示删除的 key 的个数。
keys方法:
void test4(sw::redis::Redis& redis)
{redis.set("key1", "111");redis.set("key2", "222");redis.set("key3", "333");redis.set("key4", "444");//创建容器std::vector<std::string> result;//创建插入迭代器auto it = std::back_inserter(result);redis.keys("*", it);//keys命令查询到的结果会存储到 result 中
}
keys 方法的第一个参数和 keys 命令一样,需要传入一个匹配的模式;keys 方法的第二个参数是一个插入迭代器,我们需要先准备好一个保存结果的容器,然后再创建一个插入迭代器指向容器的位置,就可以把 keys 方法获取到的结果依次通过传入的插入迭代器插入到容器的指定位置中了。
expire 和 ttl 方法:
void test5(sw::redis::Redis& redis)
{redis.set("key1", "111");//为指定键值对设置过期时间redis.expire("key1", std::chrono::seconds(10));//查看指定键值对还剩多少时间过期auto time = redis.ttl("key1");std::cout << time << std::endl;
}
expire 方法用来设置指定键值对的过期时间,ttl 方法用来查看指定键值对还剩多少时间过期,返回值是 long long 类型。
type方法:
void test6(sw::redis::Redis& redis)
{redis.set("key1", "111");std::string result = redis.type("key1");std::cout << result << std::endl;redis.lpush("key2", "111");result = redis.type("key2");std::cout << result << std::endl;redis.hset("key3", "aaa", "111");result = redis.type("key3");std::cout << result << std::endl;redis.sadd("key4", "aaa");result = redis.type("key4");std::cout << result << std::endl;
}
type 命令可以根据 key 获取 value 的类型,返回值是 string 类型。
1.10.4、string 相关方法
set 基础使用:
void test1(sw::redis::Redis& redis)
{//第一次key不存在 创建该键值对redis.set("key", "111");auto value = redis.get("key");if(value)std::cout << value.value() << std::endl;//第二次键值对已经存在,会修改原有键对应的值redis.set("key", "222");value = redis.get("key");if(value)std::cout << value.value() << std::endl;
}
当 set 方法设置的键不存在时,创建该键;当 set 方法设置的键存在时,修改键对应的 value。
set 方法设置键对应的过期时间:
void test2(sw::redis::Redis& redis)
{//给创建的键值对设置过期时间redis.set("key", "111", std::chrono::seconds(10));long long time = redis.ttl("key");std::cout << time << std::endl;
}
set 方法实现 NX,XX选项的功能:
void test3(sw::redis::Redis& redis)
{//redis-plus-plus中封装的set方法如果想要使用 set 命令 中的 NX,XX选项//就必须传入过期时间,如果不想让该键值对过期,可以传入0//NOT_EXIST 是指只有当前键不存在时,该命令才会执行成功redis.set("key", "111", 0, sw::redis::UpdateType::NOT_EXIST);//EXIST 是指只有当前键存在时,该命令才能执行成功redis.set("key", "222", 0, sw::redis::UpdateType::EXIST);}
实现该功能要通过第四个参数实现,一旦使用第四个参数,第三个参数(过期时间)就必须传入,如果不想让该键过期,可以将过期时间设置为0。
mset 方法:
void test4(sw::redis::Redis& redis)
{//第一种方式:通过列表初始化的方式一次创建多个键值对redis.mset({std::make_pair("key1", "111"), std::make_pair("key2", "222")});//第二种方式:先将多个键值对放到容器中,然后传入迭代器创建多个键值对std::vector<std::pair<std::string, std::string>> keys = {{"key3", "333"}, {"key4", "444"}};redis.mset(keys.begin(), keys.end());
}
mset 方法可以一次创建多个键值对,有两种调用方式:
- 第一种方式:通过列表初始化的方式一次创建多个键值对
- 第二种方式:先将多个键值对放到容器中,然后传入迭代器创建多个键值对
mget 方法:
void test5(sw::redis::Redis& redis)
{std::vector<std::pair<std::string, std::string>> keys = {{"key1", "111"}, {"key2", "222"}};redis.mset(keys.begin(), keys.end());std::vector<sw::redis::OptionalString> result;auto it = std::back_inserter(result);redis.mget({"key1", "key2"}, it);
}
mget方法有两个参数,第一个参数是想要查找的键,第二个参数是输出型迭代器。
getrange 和 setrange方法:
void test6(sw::redis::Redis& redis)
{redis.set("key", "abckdefg");std::string result = redis.getrange("key", 2, -1);std::cout << result << std::endl;redis.setrange("key", 2, "xyz");
}
getrange 方法可以获取指定键值对中 value 的某一部分,第一个参数是键,第二个参数是起始位置,第三个参数是结束位置,两个表示位置的参数可以传入负数。
setrange 方法可以替换指定键值对中 value 的某一部分,第一个参数是键,第二个参数用来指定从哪里开始替换,第三个参数用来指定替换为什么。
incr 和 decr 方法:
void test7(sw::redis::Redis& redis)
{redis.set("key", "100");//自增long long result1 = redis.incr("key");//自减long long result2 = redis.decr("key");
}
这两个方法只需要传入键,即可实现键对应值的自增 / 自减。
1.10.5、list 相关方法
lpush 和 lrange方法:
void test1(sw::redis::Redis& redis)
{//插入单个元素redis.lpush("key", "111");//插入一组元素,基于初始化列表redis.lpush("key", {"222", "333", "444"});//插入一组元素,基于迭代器std::vector<std::string> value = {"555", "666", "777"};redis.lpush("Key", value.begin(), value.end()); std::vector<std::string> result;auto it = std::back_inserter(result);redis.lrange("key", 0, -1, it);
}
lpush 方法有三种使用方式:
- 插入单个元素
- 使用初始化列表插入多个元素
- 使用迭代器区间插入多个元素
lrange 方法能获取指定键值对中 value 的某一部分,第一个参数是要查询的 key,第二个参数是起始位置,第三个参数是结束位置,最后一个参数是一个输出型迭代器。
注意:lpush 是头插
rpush 方法:
void test2(sw::redis::Redis& redis)
{//插入单个元素redis.rpush("key", "111");//插入一组元素,基于初始化列表redis.rpush("key1", {"222", "333", "444"});//插入一组元素,基于迭代器std::vector<std::string> value = {"555", "666", "777"};redis.rpush("Key3", value.begin(), value.end());
}
rpush 和 lpush 类似。
lpop 和 rpop方法:
void test3(sw::redis::Redis& redis)
{redis.rpush("key", {"1", "2", "3", "4"});//头删auto result = redis.lpop("key");if(result)std::cout << result.value() << std::endl;//尾删result = redis.rpop("key");if(result)std::cout << result.value() <<std::endl;
}
lpop 和 rpop 方法返回值为被删除的数据,类型是sw::redis::OptionalString。
blpop 方法:
void test4(sw::redis::Redis& redis)
{//当键不存在时,该方法会阻塞等待//直到其他客户端插入了这个键auto ret = redis.blpop("key");if(ret){std::cout << ret.value().first << std::endl;std::cout << ret.value().second << std::endl;}//同时监听多个键//除了初始化列表还可以使用迭代器区间的方式auto ret1 = redis.blpop({"key1", "key2", "key3"});//设置超时时间auto ret1 = redis.blpop({"key1", "key2", "key3"}, 10);
}
该方法返回值类型为 sw::redis::OptionalStringPair,里面包裹了一pair对象,pair对象中存储了被删除元素属于哪个 list,以及被删除元素。blpop 可以同时监听多个 key,使用初始化列表或者迭代器构造都可以,还可以设置超时时间。
llen 方法:
void test5(sw::redis::Redis& redis)
{redis.lpush("key", {"111", "222", "333"});long long len = redis.llen("key");std::cout << len << std::endl;
}
该方法传入键获取 value 的个数。
1.10.6、set 相关方法
sadd 和 smembers 方法:
void test1(sw::redis::Redis& redis)
{//插入一个元素redis.sadd("key", "111");//插入多个元素 通过初始化列表redis.sadd("key", {"222", "333", "444"});//插入多个元素 通过迭代器区间std::vector<std::string> value = {"555", "666"};redis.sadd("key", value.begin(), value.end());std::vector<std::string> result;auto it = std::back_inserter(result);redis.smembers("key", it);
}
sismember 方法:
void test2(sw::redis::Redis& redis)
{redis.sadd("key", {"111", "222", "333"});bool result = redis.sismember("key", "111");
}
传入一个键和 value,判断当前键中是否存在这样一个 value,返回值类型为 bool。
scard 方法:
void test3(sw::redis::Redis& redis)
{redis.sadd("key", {"111", "222", "333"});long long result = redis.scard("key");std::cout << result << std::endl;
}
传入键,返回当前键中有多少 value。返回值类型为 long long。
spop 方法:
void test4(sw::redis::Redis& redis)
{redis.sadd("key", {"111", "222", "333"});auto result = redis.spop("key");if(result)std::cout << result.value() << std::endl;
}
传入键,随机删除当前键中的某一个 value,返回值为被删除元素,类型为:sw::redis::OptionalString。
sinter 方法:
void test5(sw::redis::Redis& redis)
{redis.sadd("key1", {"111", "222", "333"});redis.sadd("key2", {"111", "222", "444"});std::set<std::string> result;auto it = std::inserter(result, result.end());//求交集redis.sinter({"key1", "key2"}, it);
}
该方法两个参数,第一个参数通过列表初始化的方式传入多个键,第二个参数是一个输出型迭代器,该方法会将传入的键对应的值的交集放到迭代器指向的容器中。
sinterstore 方法:
void test6(sw::redis::Redis& redis)
{redis.sadd("key1", {"111", "222", "333"});redis.sadd("key2", {"111", "222", "444"});long long len = redis.sinterstore("key3", {"key1", "key2"});}
该方法两个参数,第一个参数表示将求出的交集放到哪个键值对中,第二个参数表示求哪些键对应的值的交集。返回值表示交集的元素个数。
1.10.7、hash 相关方法
hset 和 hget 方法:
void test1(sw::redis::Redis& redis)
{//插入一对元素redis.hset("key", "f1", "111");//通过构造pair的方式插入一对元素redis.hset("key", std::make_pair("f2", "222"));//通过列表初始化插入多对元素redis.hset("key",{std::make_pair("f3", "333"),std::make_pair("f4", "444")});//通过容器的迭代器区间插入多对元素std::vector<std::pair<std::string, std::string>> fields = {std::make_pair("f5", "555"), std::make_pair("f6", "666")};redis.hset("key", fields.begin(), fields.end());//获取元素auto result = redis.hget("key", "f1");if(result)std::cout << result.value() << std::endl;
}
hexists 方法:
void test2(sw::redis::Redis& redis)
{redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");bool result = redis.hexists("key", "f1");
}
查找某一对 value 是否存在,返回值为 bool 类型。
hdel 方法:
void test3(sw::redis::Redis& redis)
{redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");long long result = redis.hdel("key", "f1");result = redis.hdel("key", {"f2", "f3"});
}
可以一次删除一对 value,也可以通过列表初始化一次删除多对 value。返回值为 long long 类型,表示删除了多少个元素。
hlen 方法:
void test4(sw::redis::Redis& redis)
{redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");long long lens = redis.hlen("key");
}
该方法传入键,返回传入的键中的元素个数,返回值为 long long 类型。
hkeys 和 hvals 方法:
void test5(sw::redis::Redis& redis)
{redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");std::vector<std::string> fields;auto it = std::back_inserter(fields);redis.hkeys("key", it);std::vector<std::string> values;auto itValues = std::back_inserter(values);redis.hvals("key", itValues);
}
这两个方法都需要传入键和输出型迭代器,结果会被放入输出型迭代器指向的容器中。
hmset 和 hmget 方法:
void test6(sw::redis::Redis& redis)
{//列表初始化redis.hmset("key", {std::make_pair("f1", "111"),std::make_pair("f2", "222"),std::make_pair("f3", "333")});//迭代器区间std::vector<std::pair<std::string, std::string>> pairs = {std::make_pair("f4", "444"),std::make_pair("f5", "555"),std::make_pair("f6", "666")};redis.hmset("key", pairs.begin(), pairs.end());std::vector<std::string> values;auto it = std::back_inserter(values);//这里第二个参数也可以使用迭代器区间redis.hmget("key", {"f1", "f2", "f3"}, it);
}
1.10.8、zset 相关方法
zadd 和 zrange方法:
void test1(sw::redis::Redis& redis)
{redis.zadd("key", "zhansan", 99);redis.zadd("key", {std::make_pair("wangwu", 91),std::make_pair("lisi", 95)});std::vector<std::pair<std::string, double>> members = {std::make_pair("abc", 55),std::make_pair("bcd", 66)};redis.zadd("key", members.begin(), members.end());std::vector<std::string> membersResult;auto it = std::back_inserter(membersResult); redis.zrange("key", 0, -1, it);std::vector<std::pair<std::string, double>> membersWithScore;auto it2 = std::back_inserter(membersWithScore);redis.zrange("key", 0, -1, it2);
}
zrange 支持两种主要的风格,一种是只查询 member,不带 score;一种是查询 member,同时带着 score。而我们查询到的结果是哪种类型,主要看传入的插入迭代器指向的容器的类型,如果指向的容器只包含一个 string,就只查询 member;如果指向的容器包含 pair,里面是 string 和 double,就会查询 member 带 score。
zcard 方法:
void test2(sw::redis::Redis& redis)
{redis.zadd("key", "zhangsan", 10);redis.zadd("key", "lisi", 20);redis.zadd("key", "wangwu", 30);redis.zadd("key", "zhaoliu", 40);//获取元素个数long long result = redis.zcard("key");
}
该方法可以获取指定键中的元素个数。返回值类型为 long long。
zrem 方法:
void test3(sw::redis::Redis& redis)
{redis.zadd("key", "zhangsan", 10);redis.zadd("key", "lisi", 20);redis.zadd("key", "wangwu", 30);redis.zadd("key", "zhaoliu", 40);//删除元素long long ret = redis.zrem("key", "zhangsan");
}
该方法可以像示例代码中那样删除单个元素,也可以使用列表初始化删除多个,或者使用迭代器区间删除多个。返回值类型为 long long,表示删除的元素个数。
zscore 方法:
void test3(sw::redis::Redis& redis)
{redis.zadd("key", "zhangsan", 10);redis.zadd("key", "lisi", 20);redis.zadd("key", "wangwu", 30);redis.zadd("key", "zhaoliu", 40);auto score = redis.zscore("key", "zhangsan");if(score)std::cout << score.value() << std::endl;
}
zrank 方法:
void test3(sw::redis::Redis& redis)
{redis.zadd("key", "zhangsan", 10);redis.zadd("key", "lisi", 20);redis.zadd("key", "wangwu", 30);redis.zadd("key", "zhaoliu", 40);auto ret = redis.zrank("key", "zhangsan");if(ret)std::cout << ret.value() << std::endl;
}