Redis基本数据类型

之前我们提到过,redis支持很多不同的数据类型,其中最基础、最常用的数据类型有 5 种,它们分别是:字符串类型、列表类型、哈希表类型、集合类型、有序集合类型,本文我们便来一一了解一下这几种数据类型的使用。

命令参考:菜鸟教程-Redis

字符串类型

字符串类型的全称是 Simple Dynamic Strings 简称 SDS,中文意思是:简单动态字符串。它是以键值对 key-value 的形式进行存储的,根据 key 来存储和获取 value 值,它的使用相对来说比较简单,但在实际项目中应用非常广泛。

字符串类型使用

字符串的操作命令有很多,但大体可分为以下几类:

  • 单个键值对操作
  • 多个键值对操作
  • 数字统计

单个键值对操作

添加键值对

语法:set key value [expiration EX seconds|PX milliseconds] [NX|XX] 示例:

1
2
127.0.0.1:6379> set k1 v1
OK
获取键值对

语法:get key 示例:

1
2
127.0.0.1:6379> get k1
"v1"
给元素追加值

语法:append key value 示例:

1
2
3
4
5
6
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> append k1 append
(integer) 5
127.0.0.1:6379> get k1
"v1append"
查询字符串的长度

语法:strlen key 示例:

1
2
127.0.0.1:6379> strlen k1
(integer) 5

多个键值对操作

创建一个或多个键值对

语法:mset key value [key value …] 示例:

1
2
127.0.0.1:6379> mset k2 v2 k3 v3
OK

Tips:mset 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,不会出现某些 key 被更新,而另一些 key 没被更新的情况。

查询一个或多个元素

语法:mget key [key …] 示例:

1
2
3
127.0.0.1:6379> mget k2 k3
1) "v2"
2) "v3"

数字统计

在 Redis 中可以直接操作整型和浮点型,例如可以直接使用命令来加、减值。

给整数类型的值加 1

语法:incr key 示例:

1
2
3
4
5
6
127.0.0.1:6379> get k1
"3"
127.0.0.1:6379> incr k1
(integer) 4
127.0.0.1:6379> get k1
"4"
给整数类型的值减 1

语法:decr key 示例:

1
2
3
4
5
6
127.0.0.1:6379> get k1
"4"
127.0.0.1:6379> decr k1
(integer) 3
127.0.0.1:6379> get k1
"3"
根据 key 减去指定的值

语法:decrby key decrement 示例:

1
2
3
4
5
6
127.0.0.1:6379> get k1
"3"
127.0.0.1:6379> decrby k1 2
(integer) 1
127.0.0.1:6379> get k1
"1"

如果 key 不存在,则会先初始化此 key 为 0 ,然后再执行减法操作:

1
2
3
4
5
6
127.0.0.1:6379> get k2
(nil)
127.0.0.1:6379> decrby k2 3
(integer) -3
127.0.0.1:6379> get k2
"-3"
根据 key 加指定的整数值

语法:incrby key increment 示例:

1
2
3
4
5
6
127.0.0.1:6379> get k1
"1"
127.0.0.1:6379> incrby k1 2
(integer) 3
127.0.0.1:6379> get k1
"3"

如果 key 不存在,则会先初始化此 key 为 0 ,然后再执行加整数值的操作:

1
2
3
4
5
6
127.0.0.1:6379> get k3
(nil)
127.0.0.1:6379> incrby k3 5
(integer) 5
127.0.0.1:6379> get k3
"5"
根据 key 加上指定的浮点数

语法:incrbyfloat key increment 示例:

1
2
3
4
5
6
127.0.0.1:6379> get k3
"5"
127.0.0.1:6379> incrbyfloat k3 4.9
"9.9"
127.0.0.1:6379> get k3
"9.9"

如果 key 不存在,则会先初始化此 key 为 0 ,然后再执行加浮点数的操作:

1
2
3
4
5
6
127.0.0.1:6379> get k4
(nil)
127.0.0.1:6379> incrbyfloat k4 4.4
"4.4"
127.0.0.1:6379> get k4
"4.4"

字典类型

字典类型 (Hash) 又被成为散列类型或者是哈希表类型,它是将一个键值 (key) 和一个特殊的“哈希表”关联起来,这个“哈希表”表包含两列数据:字段和值。

字典类型的存储结构如图所示:

哈希表存储结构.png

我们也可以使用字典类型来存储用户信息等,并且使用字典类型来存储此类信息,是不需要手动序列化和反序列化数据的,所以使用起来更加的方便和高效。

字典类型使用

字典类型的操作命令大体可分为以下几类:

  • 单个元素的操作
  • 多个元素的操作

单个元素的操作

插入单个元素

语法:hset key field value 示例:

1
2
3
4
127.0.0.1:6379> hset myhash key1 value1
(integer) 1
127.0.0.1:6379> hset myhash key2 value2
(integer) 1
当某键不存在时,插入数据

语法:hsetnx key field value 示例:

1
2
3
4
127.0.0.1:6379> hsetnx myhash k4 v4
(integer) 1
127.0.0.1:6379> hget myhash k4
"v4"

如果尝试插入已存在的键,不会改变原来的值,示例如下:

1
2
3
4
127.0.0.1:6379> hsetnx myhash k4 val4
(integer) 0
127.0.0.1:6379> hget myhash k4
"v4"

尝试修改已经存在的 k4 赋值为 val4,但并没有生效,查询 k4 的结果依然是原来的值 v4。

查询单个元素

语法:hget key field 示例:

1
2
127.0.0.1:6379> hget myhash key1
"value1"
删除 key 中的一个或多个元素

语法:hdel myhash field [field …] 示例:

1
2
127.0.0.1:6379> hdel myhash key1 key2
(integer) 1

注意:不能使用类似于 hdel myhash 的命令删除整个 Hash 值的。

某个整数值累加计算

语法:hincrby key field increment 示例:

1
2
3
4
5
6
127.0.0.1:6379> hset myhash k3 3
(integer) 1
127.0.0.1:6379> hincrby myhash k3 2
(integer) 5
127.0.0.1:6379> hget myhash k3
"5"

多个元素的操作

插入一个或多个元素

语法:hmset key field value [field value …] 示例:

1
2
3
4
5
127.0.0.1:6379> hmset myhash k1 val1 k2 val2
OK
127.0.0.1:6379> hmget myhash k1 k2
1) "val1"
2) "val2"
查询一个或多个元素

语法:hmget key field [field …] 示例:

1
2
3
127.0.0.1:6379> hmget myhash k1 k2
1) "v1"
2) "v2"
查询某个 key 的所有字段

语法:hkeys key 示例:

1
2
3
127.0.0.1:6379> hkeys myhash
1) "key1"
2) "key2"
查询某个 key 的所有值

语法:hvals key 示例:

1
2
3
127.0.0.1:6379> hvals myhash
1) "value1"
2) "value2"
查询某个 key 的所有字段和值

语法:hgetall key 示例:

1
2
3
4
5
127.0.0.1:6379> hgetall myhash
1) "k1"
2) "v1"
3) "k2"
4) "v2"

列表类型

列表类型 (List) 是一个使用链表结构存储的有序结构,它的元素插入会按照先后顺序存储到链表结构中,因此它的元素操作 (插入\删除) 时间复杂度为 O(1),所以相对来说速度还是比较快的,但它的查询时间复杂度为 O(n),因此查询可能会比较慢。

列表类型的结构如下所示:

列表类型使用-列表结构图.png

列表类型的使用

基础使用

给列表添加一个或多个元素

语法:lpush key value [value …] 示例:

1
2
3
4
5
6
127.0.0.1:6379> lpush list 1 2 3
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
给列表尾部添加一个或多个元素

语法:rpush key value [value …] 示例:

1
2
3
4
5
6
127.0.0.1:6379> rpush list 1 2 3
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
返回列表指定区间内的元素

语法:lrange key start stop 示例:

1
2
3
4
127.0.0.1:6379> lrange list 0 -1
"3"
"2"
"1"

其中 -1 代表列表中的最后一个元素。

获取并删除列表的第一个元素

语法:lpop key [count] 示例:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> lpop list
"d"
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "a"
获取并删除列表的最后一个元素

语法:rpop key [count]示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> rpop list
"5"
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> rpop list 2
1) "4"
2) "3"
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
根据下标获取对应的元素

语法:lindex key index 示例:

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> rpush list 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lindex list 2
"3"
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

集合类型

集合类型 (Set) 是一个无序并唯一的键值集合。

之所以说集合类型是一个无序集合,是因为它的存储顺序不会按照插入的先后顺序进行存储,如下代码所示:

1
2
3
4
5
6
127.0.0.1:6379> sadd myset v2 v1 v3
(integer) 1
127.0.0.1:6379> smembers myset
1) "v1"
2) "v3"
3) "v2"

由此可得,myset 的存储顺序并不是以插入的先后顺序进行存储的。

集合类型和列表类型的区别如下:

  • 列表可以存储重复元素,集合只能存储非重复元素;
  • 列表是按照元素的先后顺序存储元素的,而集合则是无序方式存储元素的。

集合类型使用

集合类型的功能比列表类型丰富一些,集合类型可以用来统计多个集合的交集、错集和并集。

基础使用

添加一个或多个元素

语法:sadd key member [member …] 示例:

1
2
127.0.0.1:6379> sadd myset v1 v2 v3
(integer) 3
查询集合所有元素

语法:smembers key 示例:

1
2
3
4
127.0.0.1:6379> smembers myset
1) "v1"
2) "v3"
3) "v2"
查询集合的成员数量

语法:scard key 示例:

1
2
127.0.0.1:6379> scard myset
(integer) 3
查询集合中是否包含某个元素

语法:sismember key member 示例:

1
2
3
4
127.0.0.1:6379> sismember myset v1
(integer) 1
127.0.0.1:6379> sismember myset v4
(integer) 0
从一个集合中移动一个元素到另一个集合

语法:smove source destination member 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> smembers myset
1) "v1"
2) "v3"
3) "v2"
127.0.0.1:6379> smembers myset2
1) "v1"
2) "v8"
127.0.0.1:6379> smove myset myset2 v3
(integer) 1
127.0.0.1:6379> smembers myset2
1) "v1"
2) "v8"
3) "v3"
127.0.0.1:6379> smembers myset
1) "v1"
2) "v2"
移除集合中一个或多个元素

语法:srem key member [member …] 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> smembers myset
1) "v4"
2) "v1"
3) "v3"
4) "v2"
5) "v5"
127.0.0.1:6379> srem myset v5
(integer) 1
127.0.0.1:6379> smembers myset
1) "v3"
2) "v2"
3) "v1"
4) "v4"

:使用 srem 指令,不存在的元素将会被忽略。

有序集合

有序集合类型 (Sorted Set) 相比于集合类型多了一个排序属性 score(分值),对于有序集合 ZSet 来说,每个存储元素相当于有两个值组成的,一个是有序结合的元素值,一个是排序值。有序集合的存储元素值也是不能重复的,但分值是可以重复的。

当我们把学生的成绩存储在有序集合中时,它的存储结构如下图所示:

学生存储值.png

有序列表使用

基础使用

添加一个或多个元素

语法:zadd key [NX|XX] [CH] [INCR] score member [score member …] 示例:

1
2
3
4
127.0.0.1:6379> zadd zset1 10 java
(integer) 1
127.0.0.1:6379> zadd zset1 3 golang 4 sql 1 redis
(integer) 3

可以看出有序集合的添加是 zadd 键值 分值1 元素值1 分值2 元素值2 的形式添加的。

查询所有元素列表

语法:zrange key start stop [WITHSCORES] 示例:

1
2
3
4
127.0.0.1:6379> zrange zset 0 -1
1) "redis"
2) "mysql"
3) "java"

其中 -1 表示最后一个元素,查询结果包含开始和结束元素。

删除一个或多个元素(根据元素值)

语法:zrem key member [member …] 示例:

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> zrangebyscore zset1 0 -1 #查询所有元素
1) "golang"
2) "redis"
3) "sql"
4) "java"
127.0.0.1:6379> zrem zset1 redis sql #删除元素:reids、sql
(integer) 2
127.0.0.1:6379> zrange zset1 0 -1 #查询所有元素
1) "golang"
2) "java"

删除命令中如果包含了不存在的元素,并不会影响命令的正常执行,不存在的元素将会被忽略。

查询某元素的 score 值

语法:zscore key member 示例:

1
2
127.0.0.1:6379> zscore zset1 redis
"1"
查询 score 区间内元素

语法:zrangebyscore key min max [WITHSCORES] [LIMIT offset count] 示例:

1
2
3
4
5
127.0.0.1:6379> zrangebyscore zset1 3 10
1) "golang"
2) "redis"
3) "sql"
4) "java"
查询某元素排名

语法:zrank key member 示例:

1
2
3
4
5
6
127.0.0.1:6379> zadd zset 5 redis 10 java 8 mysql #创建有序集合
(integer) 3
127.0.0.1:6379> zrank zset java #查询元素排序
(integer) 2
127.0.0.1:6379> zrank zset redis
(integer) 0

可以看出,排名是从 0 开始的,排名可以理解为元素排序后的下标值。

参考: