Redis:数据类型

来自Wikioe
跳到导航 跳到搜索


关于

Redis 以 key-value 存储数据,“key”为 String,其“数据类型”是指“value 的类型”;


Redis 支持五种数据类型:

数据类型 说明
string 字符串类型
list 列表类型
hash 哈希类型
set 集合类型
zset(sorted set) 有序集合类型

Redis 的 5 种数据类型

String


String 类型是 Redis 中最简单的数据结构。它既可以存储文字(例如"hello world"),又可以存储数字(例如整数 10086 和浮点数 3.14),还可以存储二进制数据(例如 10010100)。


字符串类型:字符串类型是Redis中最基本的数据类型;

Redis-string.png
  • 它能存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON化的对象甚至是一张图片。


String 相关命令
命令 说明
append <key> <value> 如果 key 存在且是字符串, 则将 value 追加到 key 原来旧值的末尾;
  • 如果 key 不存在,就简单地将给定 key 设为 value ,就像执行 SET key value 一样;
strlen <key> 返回 key 所储存的字符串值的长度;
get <key> 获取 key 中设置的字符串值;
set <key> <value> 将字符串值 value 设置到 key 中;
mget <key> [<key>] 获取所有(一个或多个)给定 key 的值
mset <key> <value> [<key> <value>] 同时设置一个或多个 key-value 对
setnx <key> <value> setnx 是“set if not exists”的简写,如果key不存在,则设置值,存在则不设置值;
msetnx <key> <value> [<key> <value>] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在时才能设置成功,否则只要有一个key存在都会失败
getbit <key> offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
setbit <key> offset <value> 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
getrange <key> <start> <end> 获取 key 中字符串值从 start 开始 到 end 结束 的子字符串;
setrange <key> <offset> <value> 从指定的位置开始将 key 的值替换为新的字符串;
setex <key> <seconds> <value> set expire”的简写,设置 key 的值 ,并将 key 的生存时间设为 seconds (以秒为单位) ;
psetex <key> milliseconds <value> 这个命令和 setex 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 setex 命令那样,以秒为单位。
getset <key> <value> 设置 key 的值为 value ,并返回 key 的旧值;
incr <key> 将 key 中储存的数字值加 1;
  • 如果 key 不存在,则 key 的值先被初始化为 0 再执行 INCR 操作;
  • (只能对数字类型的数据操作,否则:“(error) ERR value is not an integer or out of range”);
decr <key> 将 key 中储存的数字值减 1;
  • (同上);
incrby <key> <increment> 将 key 所储存的值加上增量值;
  • 如果 key 不存在,则 key 的值先被初始化为 0 再执行 INCRBY 命令;
decrby <key> <decrement> 将 key 所储存的值减去减量值;
  • 如果 key 不存在,则 key 的值先被初始化为 0 再执行 DECRBY 命令;
incrbyfloat <key> <increment> 为 key 中所储存的值加上浮点数增量 increment;
  • 如果 key 不存在,那么 incrbyfloat 会先将 key 的值设为 0 ,再执行加法操作。
  • 当以下任意一个条件发生时,返回一个错误:
    1. key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
    2. key 当前的值或者给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)
bitcount <key> <start> <end> 计算给定字符串中,被设置为 1 的比特位的数量;
  • start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。
  • 不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
bitop <operation> <destkey> <key> [<key> ...] 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上;
  • operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:
    1. BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
    2. BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
    3. BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
    4. BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey 。
    • 除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。
  • 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0 。
  • 空的 key 也被看作是包含 0 的字符串序列。

List


Redis 的 List 类型是基于【双向链表】实现的,可以支持正向、反向查找和遍历。从用户角度来说,List列表是简单的字符串列表,字符串按照添加的顺序排序。可以添加一个元素到List列表的头部(左边)或者尾部(右边)。一个List列表最多可以包含232-1个元素(最多可超过 40亿 个元素)。


List列表的典型应用场景:
   网络社区中最新的发帖列表、简单的消息队列、最新新闻的分页列表、博客的评论列表、排队系统等等。

举个具体的例子,在“双11”秒杀、抢购这样的大型活动中,短时间内有大量的用户请求发向服务器,而后台的程序不可能立刻响应每一个用户的请求,有什么好的办法来解决这个问题呢?
   我们需要一个排队系统。根据用户的请求时间,将用户的请求放入 List 队列中,后台程序依次从队列中获取任务,处理并将结果返回到结果队列。换句话说,通过List队列,可以将并行的请求转换成串行的任务队列,之后依次处理。


列表类型:简单的字符串列表,按照插入顺序排序。

Redis-list.png
  • 可以添加一个元素到列表的头部(左边)或者尾部(右边);
  • 一个列表最多可以包含 2^32 - 1 (40多亿)个元素。
  • List 列表的下标是从 0 开始的,index 为的时候是从后向前数(-1 表示最后一个元素)。当下标超出边界时,会返回 nil


List 相关命令
命令 说明
lpush <key> <value> [<value>] 将一个或多个值 value 插入到列表 key 的表头(最左边)
rpush <key> <value> [<value>] 将一个或多个值 value 插入到列表 key 的表尾(最右边)
lpushx <key> <value> 将一个值插入到已存在的列表头部,当且仅当 key 存在并且是一个列表
  • 和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不做。
rpushx <key> <value> 为已存在的列表添加值,当且仅当 key 存在并且是一个列表
  • 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。
lpop <key> 从左边获取列表 key 的一个元素,并将该元素移除
rpop <key> 从右边获取列表 key 的一个元素,并将该元素移除
blpop <key> [<key>] timeout 移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
  • 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的元素。
brpop <key> [<key>] timeout 移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
  • 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的元素。
rpoplpush <source> <destination> 将列表 source 中的最后一个元素(尾元素)弹出插入到目标列表(destination),作为目标列表的的头元素
brpoplpush <source> <destination> timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
llen <key> 获取列表 key 的长度
lindex <key> <index> 获取列表 key 中下标为指定 index 的元素
lset <key> <index> <value> 将列表 key 下标为 index 的元素的值设置为 value
linsert <key> BEFORE|AFTER <pivot> <value> 将值 value 插入到列表 key 当中位于值 pivot 之前或之后的位置
lrange <key> <start> <stop> 获取列表 key 中指定区间内的元素
  • 0 表示列表的第一个元素,以 1 表示列表的第二个元素, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
lrem <key> <count> <value> 从左到右删除列表中指定个数(count)的“与指定value值相等的”value
ltrim <key> <start> <stop> 删除指定区域外的元素,比如“LTRIM list 0 2” ,表示只保留列表 list 的前三个元素,其余元素全部删除

Hash


Redis 中的 Hash 哈希表是一个 String 类型的 Field 字段和 Value 值之间的映射表,类似于 Java 中的 HashMap。

一个哈希表由多个“字段-值”对(Field-Value Pair)组成,Value 值可以是文字、整数、浮点数或者二进制数据。

在同一个 Hash 哈希表中,每个 Field 字段的名称必须是唯一的。这一点和 Java 中 HashMap 的 Key 键的规范要求也是八九不离十的。


哈希类型:是一个 String 类型的 fieldvalue 的映射表;

Redis-hash.png
  • Hash 特别适合用于存储对象
  • 每个 hash 可以存储 2^32 - 1 (40多亿)个键值对。


Hash 相关命令
命令 说明
hget <key> <field> 获取哈希表 key 中给定域 field 的值
hgetall <key> 获取哈希表 key 中所有的域和值
hset <key> <field> <value> 将哈希表 key 中的域 field 的值设为 value
hsetnx <key> <field> <value> 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在的时候才设置,否则不设置
hmset <key> <field> <value> [<field> <value>] 同时将多个 field-value (域-值)对设置到哈希表 key 中
hmget <key> <field> [<field>] 获取哈希表 key 中一个或多个给定域的值
hkeys <key> 查看哈希表 key 中的所有 field 域
hvals <key> 查看哈希表 key 中所有域的值
hexists <key> <field> 查看哈希表 key 中,给定域 field 是否存在
hlen <key> 获取哈希表 key 中域 field 的个数
hdel <key> <field> [<field>] 删除哈希表 key 中的一个或多个指定域 field
hincrby <key> <field> <increment> 为哈希表 key 中的域 field 的值加上增量 increment
hincrbyfloat <key> <field> <increment> 为哈希表 key 中的域 field 加上浮点数增量 increment
hscan <key> cursor [MATCH pattern] [COUNT count] 迭代哈希表中的键值对【???】

Set


Set 集合也是一个列表,不过它的特殊之处在于它是可以自动去掉重复元素的。

Set 集合类型的使用场景是:当需要存储一个列表,而又不希望有重复的元素(例如ID的集合)时,使用 Set 是一个很好的选择。


特点:
1、Set 类型拥有一个命令,它可用于判断某个元素是否存在,而 List 类型并没有这种功能的命令。
2、通过 Set 集合类型的命令可以快速地向集合添加元素,或者从集合里面删除元素,也可以对多个 Set 集合进行集合运算,例如并集、交集、差集。


集合类型:String 类型的无序集合,集合成员(member)是唯一的,即集合中不能出现重复的数据

Redis-set.png
  • Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
  • 集合中最大的成员数为 2^32 - 1 (40多亿)。


Set 相关命令
命令 说明
sadd <key> <member> [<member>] 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将不会再加入
srem <key> <member> [<member>] 删除集合 key 中的一个或多个 member 元素
spop <key> [count] 随机从集合中删除一个元素
smove <source> <destination> <member> 将 member 元素从一个集合移动到另一个集合
scard <key> 获取集合里面的元素个数
smembers <key> 获取集合 key 中的所有成员元素
sismember <key> <member> 判断 member 元素是否是集合 key 的成员
srandmember <key> [count] 随机返回集合中的一个元素
sdiff <key> [<key>] 返回第一个集合与其他集合之间的差异。
sdiffstore <destination> <key> [<key>] 返回给定所有集合的差集并存储在 destination 中
sinter <key> [<key>] 返回给定所有集合的交集
sinterstore <destination> <key> [<key>] 返回给定所有集合的交集并存储在 destination 中
sunion <key> [key2] 返回所有给定集合的并集
sunionstore <destination> <key> [<key>] 所有给定集合的并集存储在 destination 集合中
sscan <key> cursor [MATCH pattern] [COUNT count] 迭代集合中的元素

Zset(sorted set)


Zset 有序集合和 Set 集合的使用场景类似,区别是有序集合会根据提供的 score 参数来进行自动排序。

当需要一个不重复的且有序的集合列表,那么就可以选择Zset有序集合类型。常用案例:游戏中的排行榜。


Zset 有序集合和 Set 集合不同的是,有序集合的每个元素,都关联着一个分值(Score),这是一个浮点数格式的关联值。Zset 有序集合会按照分值(Score),按从小到大的顺序来排列有序集合中的各个元素。


有序集合类型:(有序的Set)不同的是 Zset 的每个元素(member)都会关联一个分数(score,分数可以重复),Redis 通过分数来为集合中的成员进行从小到大的排序。

Redis-zset.png
  • 有序集合的成员是唯一的,但分数(score)却可以重复。
  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
  • 集合中最大的成员数为 2^32 - 1 (40多亿)。


Zset 相关命令
命令 说明
zadd <key> [NX|XX] [CH] [INCR] <score> <member> [<score> <member>] 将一个或多个 member 元素及其 score 值加入到有序集合 key 中
zscore <key> <member> 返回有序集中,成员的分数值
zincrby <key> <increment> <member> 有序集合中对指定成员的分数加上增量 increment
zcard <key> 获取有序集合的成员数
zcount <key> <min> <max> 计算在有序集合中指定分数区间的成员数
  • 在默认情况下,<min> 和 <max> 表示的范围,是闭区间范围区间范围(即 min≤score≤max 内的成员)。
    • 另外,可以使用 -inf+inf 分别表示有序集合中分数的最小值和最大值。
zlexcount <key> <min> <max> 计算在有序集合中指定字典区间的成员数
zrank <key> <member> 返回有序集合中指定成员的索引
zrevrank <key> <member> 返回有序集合中指定成员的索引【rev:有序集成员按分数值递减(从大到小)排序】
zrange <key> <start> <stop> [WITHSCORES] 返回有序集中指定索引区间内的成员
zrevrange <key> <start> <stop> [WITHSCORES] 返回有序集中指定索引区间内的成员【rev:有序集成员按分数值递减(从大到小)排序】
zrangebylex <key> <min> <max> [LIMIT <offset> <count>] 返回有序集中指定字典区间内的成员
zrangebyscore <key> <min> <max> [WITHSCORES] [LIMIT <offset> <count>] 返回有序集中指定分数区间内的成员
zrevrangebyscore <key> <min> <max> [WITHSCORES] [LIMIT <offset> count>] 返回有序集中指定分数区间内的成员【rev:有序集成员按分数值递减(从大到小)排序】
zrem <key> <member> [<member>] 移除有序集合 key 中的一个或多个成员
zremrangebylex <key> <min> <max> 移除有序集合中给定的字典区间的所有成员
zremrangebyrank <key> <start> <stop> 移除有序集合中给定的排名区间的所有成员
zremrangebyscore <key> <min> <max> 移除有序集合中给定的分数区间的所有成员
zinterstore <destination> <numkeys> <key> [<key>...] [WEIGHTS <weight> [<weight>...]] [AGGREGATE SUM|MIN|MAX] 计算给定的一个或多个有序集的交集,并存储在新的 key(destination)中
  • <numkeys>:给定 key 的数量;
  • WEIGHTS:为每个给定有序集分别指定一个乘法因子(multiplication factor),每个给定有序集的所有成员的 score 值在传递给聚合函数(aggregation function)之前都要先乘以该有序集的因子。
    • 如果没有指定则默认设置为 1
  • AGGREGATE:指定并集的结果集的聚合方式。
    1. 参数“SUM”:可以将所有集合中某个成员的 score 值之“和”作为结果集中该成员的 score 值;(默认)
    2. 参数“MIN”:可以将所有集合中某个成员的“最小的”score 值作为结果集中该成员的 score 值;
    3. 参数“MAX”:可以将所有集合中某个成员的“最大的”score 值作为结果集中该成员的 score 值。
  • 返回值:保存到 destination 的结果集的基数。
zunionstore <destination> <numkeys> <key> [<key>...] [WEIGHTS <weight> [<weight>...]] [AGGREGATE SUM|MIN|MAX] 计算给定的一个或多个有序集的并集,并存储在新的 key(destination)中
  • 【同上】
zscan <key> cursor [MATCH <pattern>] [COUNT <count>] 迭代有序集合中的元素(包括元素成员和元素分值)


示例:

  1. “zinterstore”:
    redis > ZADD mid_test 70 "Li Lei"
    (integer) 1
    redis > ZADD mid_test 70 "Han Meimei"
    (integer) 1
    redis > ZADD mid_test 99.5 "Tom"
    (integer) 1
    
    redis > ZADD fin_test 88 "Li Lei"
    (integer) 1
    redis > ZADD fin_test 75 "Han Meimei"
    (integer) 1
    redis > ZADD fin_test 99.5 "Tom"
    (integer) 1
    
    redis > ZINTERSTORE sum_point 2 mid_test fin_test
    (integer) 3
    
    redis > ZRANGE sum_point 0 -1 WITHSCORES     # 显示有序集内所有成员及其 score 值
    1) "Han Meimei"
    2) "145"
    3) "Li Lei"
    4) "158"
    5) "Tom"
    6) "199"
    
  2. “zunionstore”:
    redis> ZRANGE programmer 0 -1 WITHSCORES
    1) "peter"
    2) "2000"
    3) "jack"
    4) "3500"
    5) "tom"
    6) "5000"
    
    redis> ZRANGE manager 0 -1 WITHSCORES
    1) "herry"
    2) "2000"
    3) "mary"
    4) "3500"
    5) "bob"
    6) "4000"
    
    redis> ZUNIONSTORE salary 2 programmer manager WEIGHTS 1 3   # 公司决定加薪。。。除了程序员(programmer 的 WEIGHTS 为 1)。。。
    (integer) 6
    
    redis> ZRANGE salary 0 -1 WITHSCORES
    1) "peter"
    2) "2000"
    3) "jack"
    4) "3500"
    5) "tom"
    6) "5000"
    7) "herry"
    8) "6000"
    9) "mary"
    10) "10500"
    11) "bob"
    12) "12000"
    

FAQ

单个“Key”和“Value”数据大小

512 M512 M512 M!并非“1 G”。
  1. Key 的大小上限为 512 M
    • 建议 key 的大小不超过 1 KB,这样既节约存储空间,也利于 Redis 进行检索。
  2. String 类型的 value 值上限为 512 M
  3. 集合、链表、哈希等 key 类型,单个元素的 value 上限为 512 M
    • 事实上,集合、链表、哈希都可以看成由 String 类型的 key 按照一定的映射关系组合而成。

使用 Hash 的好处

应该尽量使用 Hash 哈希表而不是字符串键来缓存 Key-Value(“键-值对”)数据,优势为:方便管理、能够避免键名冲突、并且还能够节约内存。
  1. 将数据集中存放
    通过 Hash 哈希表,可以将一些相关的信息存储在同一个缓存 Key 键中,不仅方便了数据管理,还可以尽量避免误操作的发生。
  2. 避免键名冲突
    在介绍缓存 Key 的命名规范时,可以在命名键的时候,使用冒号分割符来避免命名冲突,但更好的避免冲突的办法是直接使用哈希键来存储“键-值对”数据。
  3. 减少 Key 键的内存占用
    在一般情况下,保存相同数量的“键-值对”信息,使用哈希键比使用字符串键更节约内存。
    • 因为 Redis 创建一个 Key 键都带有很多的附加管理信息(例如:这个 Key 键的类型、最后一次被访问的时间等),所以缓存的 Key 键越多,耗费的内存就越多,花在管理数据库 Key 键上的 CPU 也会越多

Set、Zset 的实现

Set、Zset 都是通过 Hash 实现的:“field - value”中“value”为空的 Hash。