Redis 数据类型
1. 实验介绍
1.1 实验内容
在本节内容中,我们将介绍 Redis 的数据类型,及其一些相关的命令使用。而对于单独的键 key 的操作,将在学习数据类型的时候了解到相关的内容,不会单独提出。
Redis 不仅是一个 key-value 的存储系统,也是一款数据结构服务器(data structure server)。Redis 的键值可以包括字符串(strings)类型,同时它还包括哈希(hashes)、列表(lists)、集合(sets)和有序集合(sorted sets)等数据类型。
1.2 实验知识点
- Redis 数据类型
- string
- list
- hash
- sets
- sorted sets
2. string
字符串是一种最基本的 Redis 值类型。Redis 字符串是二进制安全的,这意味着一个 Redis 字符串能包含任意类型的数据,例如: 一张 JPEG 格式的图片或者一个序列化的 Ruby 对象。一个字符串类型的值最多能存储 512M 字节的内容。
字符串是 Redis 中最基本的数据类型。对于字符串而言,设置及获取一个 key 的值的语法格式为:
SET key value
GET key
对于上述语法中的 SET 和 GET 来说,也是不区分大小写的,在后面的内容中,将不再说明。
首先,我们打开 redis-cli ,SET 的语法格式如下:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
对于 SET 来说,该命令就是将键 key 设定为指定的字符串值 value,而如果 key 已经保存了一个值,该操作会直接覆盖原来的值,并且忽略原始的数据类型。如下所示:
127.0.0.1:6379> SET shiyanlou001 001
OK
127.0.0.1:6379> GET shiyanlou001
"001"
对应 SET 的是 GET,使用 GET key,获得 key 的值。
我们可以使用下列语法查看键的存储类型:
TYPE key
如下所示,显示为 string:
127.0.0.1:6379> TYPE shiyanlou001
string
在上面的 SET 命令中,还有三个可选项,代表的意思如下:
- EX 设置键的过期时间,单位为秒
- PX 设置键的过期时间,单位为毫秒
- NX 在不存在该键的时候,才会设置值
- XX 只有该键存在的时候,才会设置值
过期时间是指 key 的有效时间或者说是生存时间,从设定开始,超过该时间后,key 就会自动删除。对于上述的可选项来说,在 redis-cli 中都有对应的命令,例如 SETNX,SETEX 等,但是 SET 也可以实现同样的功能,这里我们不再描述。
如下示例,我们设置一个有过期时间的键:
127.0.0.1:6379> SET test_key test_value EX 30
OK
127.0.0.1:6379> GET test_key
"test_value"
即在 30 秒后,test_key 将会失效,对于查看键的过期时间,我们可以使用如下语法:
TTL key
如下所示,查看 test_key 的过期时间(由于操作时间的不同,看到的值可能不同,这里我们显示的是还有 12 秒过期):
127.0.0.1:6379> TTL test_key
(integer) 12
关于 TTL ,如果是未设置过期时间,返回 -1,代表没有过期时间,-2 则代表该键已过期或者不存在。
# 等过了 30 秒以后再执行就会返回已过期
127.0.0.1:6379> TTL test_key
(integer) -2
# shiyanlou001 未设置就返回 -1
127.0.0.1:6379> TTL shiyanlou001
(integer) -1
对于字符串而言,还有一些其它的常用命令,简单列举如下:
# 使用 MSET 设置多个键的值
MSET key value [key value ...]
# 使用 MGET 获取多个键的值,对于不存在的键会返回特殊值 nil
MGET key [key ...]
# 使用 STRLEN 获取指定键的长度
STRLEN key
# 使用 DECR 将整数减 1
DECR key
# 使用 INCR 将整数加 1
INCR key
# 使用 DECRBY 将整数减去指定的值
DECRBY key decrement
# 使用 INCRBY 将整数加上指定的值
INCRBY key increment
# 使用 APPEND 追加一个值
APPEND key value
如下简单示例:
127.0.0.1:6379> MSET shiyanlou002 002 shiyanlou003 003 shiyanlou004 4
OK
127.0.0.1:6379> MGET shiyanlou001 shiyanlou002 shiyanlou003 shiyanlou004
1) "001"
2) "002"
3) "003"
4) "4"
127.0.0.1:6379> STRLEN shiyanlou001
(integer) 3
127.0.0.1:6379> STRLEN shiyanlou004
(integer) 1
127.0.0.1:6379> DECR shiyanlou004
(integer) 3
127.0.0.1:6379> GET shiyanlou004
"3"
127.0.0.1:6379> INCR shiyanlou004
(integer) 4
127.0.0.1:6379> GET shiyanlou004
"4"
127.0.0.1:6379> DECRBY shiyanlou004 2
(integer) 2
127.0.0.1:6379> GET shiyanlou004
"2"
127.0.0.1:6379> INCRBY shiyanlou004 10
(integer) 12
127.0.0.1:6379> GET shiyanlou004
"12"
127.0.0.1:6379> APPEND shiyanlou001 append_test
(integer) 14
127.0.0.1:6379> GET shiyanlou001
"001append_test"
3. list
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),LPUSH 命令插入一个新元素到列表头部,而RPUSH 命令插入一个新元素到列表的尾部。如果 key 不存在,将会在执行插入操作前创建一个空列表;如果 key 已存在,且对应的值不是一个列表,会返回一个错误,这一点与字符串不同。相似的,如果一个列表操作清空一个列表那么对应的 key 将被从 key 空间删除。这是非常方便的语义,因为如果使用一个不存在的 key 作为参数,所有的列表命令都会像在对一个空表操作一样。
首先,我们先尝试查看并删除上面的内容中创建的键。查找所有匹配给定的模式的键使用如下语句:
KEYS pattern
pattern 代表的是给定模式(正则表达式)。相关的内容在前面几周的学习中,已经讲述了很多次,这里只会涉及到一些通用的内容。
例如,查看所有的键:
127.0.0.1:6379> keys *
1) "shiyanlou001"
2) "shiyanlou004"
3) "shiyanlou003"
4) "shiyanlou002"
删除指定的一个或多个键使用如下语句:
DEL key [key...]
除了删除之外,我们也可以将一个键重命名,使用如下语句:
RENAME key newkey
如下示例,删除刚刚所有创建的键:
127.0.0.1:6379> DEL shiyanlou001 shiyanlou002 shiyanlou003 shiyanlou004
(integer) 4
127.0.0.1:6379> keys *
(empty list or set)
对于一个列表而言,我们可以从列表的左边或者右边,即头部或者尾部插入元素。分别使用 LPUSH 和 RPUSH 命令:
LPUSH key value [value ...]
RPUSH key value [value ...]
从列表中获取元素时使用 LRANGE。start 和 stop 为指定范围,列表中的第一个元素下标为 0。也可以为负数,例如 -2 为倒数第二个元素。
LRANGE key start stop
在获取元素之前,我们还需要获取列表的长度,使用 LLEN
LLEN key
如下的简单示例,分别使用上面介绍的关于列表的操作:
127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379> LPUSH shiyanlou001 a b c d
(integer) 4
127.0.0.1:6379> LLEN shiyanlou001
(integer) 4
127.0.0.1:6379> LRANGE shiyanlou001 0 3
1) "d"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> RPUSH shiyanlou001 e f g h
(integer) 8
127.0.0.1:6379> LLEN shiyanlou001
(integer) 8
127.0.0.1:6379> LRANGE shiyanlou001 0 7
1) "d"
2) "c"
3) "b"
4) "a"
5) "e"
6) "f"
7) "g"
8) "h"
127.0.0.1:6379> LRANGE shiyanlou001 0 -4
1) "d"
2) "c"
3) "b"
4) "a"
5) "e"
127.0.0.1:6379>
对于上述的插入操作,如果列表不存在,会创建一个列表。
而只针对插入操作,在列表不存在时,什么操作也不执行的命令,如下:
LPUSHX key value
RPUSHX key value
如下所示:
127.0.0.1:6379> LPUSHX shiyanlou001 1
(integer) 9
127.0.0.1:6379> LPUSHX shiyanlou002 1
(integer) 0
127.0.0.1:6379> RPUSHX shiyanlou002 1
(integer) 0
127.0.0.1:6379> KEYS *
1) "shiyanlou001"
127.0.0.1:6379>
移除列表中的元素可以使用 LPOP 和 RPOP
LPOP key
RPOP key
如下所示:
127.0.0.1:6379> LLEN shiyanlou001
(integer) 9
127.0.0.1:6379> LRANGE shiyanlou001 0 8
1) "1"
2) "d"
3) "c"
4) "b"
5) "a"
6) "e"
7) "f"
8) "g"
9) "h"
127.0.0.1:6379> LPOP shiyanlou001
"1"
127.0.0.1:6379> LLEN shiyanlou001
(integer) 8
除了这些常用的操作之外,还有很多其它的命令,这里就不一一列举了。
Redis 字符串和列表类型操作视频:
4. hash
Redis Hashes 是字符串字段和字符串值之间的映射,因此他们是展现对象的完美数据类型。一个带有一些字段的 hash 仅仅需要一块很小的空间存储,因此你可以存储数以百万计的对象在一个小的 Redis 实例中。哈希主要用来表现对象,但也能够存储许多元素,因此可以将哈希用于许多其他的任务。一个 hash 最多可以包含 2^32-1 个 key-value 键值对,但这已经超过 40 亿了。
对于设置和获取 hash 字段和值的语法如下:
HSET key field value
HGET key field value
首先,我们删除 shiyanlou001 的列表,然后设置 hash 集 shiyanlou001 的字段,并获取值。
127.0.0.1:6379> DEL shiyanlou001
(integer) 1
127.0.0.1:6379> HSET shiyanlou001 username aiden
(integer) 1
127.0.0.1:6379> HGET shiyanlou001 username
"aiden"
使用 HSET 设置字段的值时,如果指定的 key 即哈希集不存在,则会创建一个新的哈希集并与 key 关联。
对于多个字段值的设置和获取可以使用如下语句:
HMSET key field value [field value]
HMGET key field [field ...]
简单示例:
127.0.0.1:6379> HMSET shiyanlou001 age 30 sex man company shiyanlou
OK
127.0.0.1:6379> HMGET shiyanlou001 username age sex company
1) "aiden"
2) "30"
3) "man"
4) "shiyanlou"
以及一些其它的命令:
# 获取所有字段
HKEYS key
# 获取所有的值
HVALS key
# 获取所有的字段和值
HGETALL key
# 获取所有字段的数量
HLEN key
# 删除一个或者多个字段
HDEL key field [field ...]
# 判断字段是否存在于 Hash 中
HEXISTS key field
Redis Hash 操作视频:
5. set
Redis 集合(Set)是一个无序的字符串集合。你可以以 O(1) 的时间复杂度 (无论集合中有多少元素时间复杂度都是常量)完成添加,删除,以及测试元素是否存在。Redis 集合拥有不允许包含相同成员的属性,多次添加相同的元素,最终在集合里也只会有一个元素。实际上这些意味着在添加元素的时候无须检测元素是否存在。
Redis 集合有许多非常有趣的事情,比如:支持一些服务端的命令从现有的集合出发去进行集合运算,因此就可以在非常短的时间内进行合并(unions), 求交集(intersections),找出不同的元素(differences of sets)。
这里我们讲述集合的有关操作。首先是,添加一个或多个元素到集合中,以及获取集合中的所有元素。语法格式如下:
SADD key member [member ...]
SMEMBERS key
这里的 member 代表的是集合中的元素,也称成员,如下示例:
127.0.0.1:6379> SADD shiyanlou002 a b 1 2
(integer) 4
127.0.0.1:6379> SMEMBERS shiyanlou002
1) "2"
2) "1"
3) "b"
4) "a"
以及一些常见的其它操作,简单列举:
# 获取集合中元素的数量
SCARD key
# 从集合中随机删除一个或多个元素
SPOP key [count]
# 从集合中删除指定的一个或者多个元素
SREM key member [member ...]
# 判断一个给定的值是该集合的成员,如果是就返回 1 ,否就返回 0 。
SISMEMBER key member
简单示例:
127.0.0.1:6379> SCARD shiyanlou002
(integer) 4
127.0.0.1:6379> SPOP shiyanlou002 2
1) "b"
2) "1"
127.0.0.1:6379> SMEMBERS shiyanlou002
1) "2"
2) "a"
127.0.0.1:6379> SREM shiyanlou002 2
(integer) 1
127.0.0.1:6379> SMEMBERS shiyanlou002
1) "a"
127.0.0.1:6379> SISMEMBER shiyanlou002 a
(integer) 1
127.0.0.1:6379> SISMEMBER shiyanlou002 b
(integer) 0
Redis Set 操作视频:
6. sorted set
Redis 有序集合与普通集合非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每一个成员都关联了一个评分,这个评分被用来按照从最低分到最高分的方式排序集合中的成员。
集合的成员是唯一的,但是评分可以是重复。使用有序集合可以以非常快的速度(O(log(N)))添加,删除和更新元素。因为元素是有序的,所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。
在有序集合中,你可以很快捷的访问一切你需要的东西:有序的元素,快速的存在性测试,快速访问集合的中间元素!简而言之使用有序集合你可以完成许多对性能有极端要求的任务,而那些任务使用其他类型的数据库真的是很难完成的。
经过上面的学习我们会发现,对于 Redis 中各种数据类型相关的操作命令,都有一定的规律。所以这里我们只是简单列举命令并示例。
给有序集合添加成员,指定:分数/成员(score/member)。如果成员已经存在,则会更新 score 并更改排序位置。 Redis 使用的 score 为双精度 64 位的浮点数。
ZADD key NX|XX [INCR] score member [score member ...]
在 REDIS 3.x 之后的版本中支持一些参数,分别如下所示:
- NX: 不更新存在的元素,只添加新成员。
- XX: 仅更新存在的元素
- CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD 返回值只计算新添加成员的数量。
- INCR: 当 ZADD 指定这个选项时,成员的操作就等同 ZINCRBY 命令,对成员的分数进行递增操作。
除此之外,一些其它的常用命令
# 获得成员数量
ZCARD key
# 根据 Index 获得指定的成员列表
ZRANGE key start stop
# 确定成员的索引
ZRANK key member
# 删除一个或者多个成员
ZREM key member [member ...]
# 获取一个成员的分数(score)
ZSCORE key member
使用示例如下:
# 添加有序集的分数/成员
127.0.0.1:6379> ZADD shiyanlou003 NX 1 a 2 b 3 c
(integer) 3
# 获取成员数量
127.0.0.1:6379> ZCARD shiyanlou003
(integer) 3
# 根据 Index 获得指定的成员列表
127.0.0.1:6379> ZRANGE shiyanlou003 0 2
1) "a"
2) "b"
3) "c"
# 确定成员 b 的索引
127.0.0.1:6379> ZRANK shiyanlou003 b
(integer) 1
# 获取成员的分数
127.0.0.1:6379> ZSCORE shiyanlou003 b
"2"
# 删除多个成员
127.0.0.1:6379> ZREM shiyanlou003 a b
(integer) 2
# 获取成员数量
127.0.0.1:6379> ZCARD shiyanlou003
(integer) 1
# 根据 Index 获得指定的成员列表
127.0.0.1:6379> ZRANGE shiyanlou003 0 1
1) "c"
7. 总结
通过本节实验的学习,认识到了 Redis 的相关数据类型以及各个数据类型的基本操作。
- strings
- list
- hash
- sets
- sort sets