引言
正所谓万丈高楼平地起,学习一项技术都需要从其基础知识开始。上一篇介绍了Redis在Linux环境下的安装步骤,本文主要介绍了Redis的基础知识,包括数据结构以及常用命令等。废话不多说,我们直接开始吧。
- Redis基础数据结构
- Redis常用命令
Redis基础数据结构
Redis是一款高性能的key-value数据库,性能极高,它的读数据速度是110000次/s,写数据的速度为81000次/s。对于Redis来说,它的系统内部通过一个redisObject对象来保存key和value这样的键值对数据,可以类比为Java中的HashMap,只是Redis所有的key都是string。它包含了5种基础数据结构,分别为:string(字符串)、list(列表)、set(集合)、hash(哈希)以及zset(有序集合)。这五种基础数据结构是掌握Redis的关键,同时也是面试中常见的问题点。
这五种数据类型,每种数据结构的内部都至少包含两种数据编码的方式,这对用户来说是完全透明的,Redis自身会根据实际需要选择合适的数据编码格式进行数据存储。我们可以通过OBJECT ENCODING key来查看具体的编码方式。
1、string
字符串Redis数据库中最简单的数据结构,在Redis中所有的数据库所有的key值都是通过唯一的字符串进行指定。差别的是key值所对应的value数据结构不同而已。当Redis的key所对应的value为string时,它经常被用来缓存用户信息等。
Redis的字符串是动态扩展的动态字符串,它的内部结构类似于Java中的ArrayList,在初次分配内存空间的时候回采取分配的比实际大的预分配策略,这样可以减少内存频繁分配的开销。
常用命令,如下所示:
(1)set name taomeng
(2)get name
批量操作可以节省网络流量,如下所示:
同时我们可以对设置的key进行过期设置,过期时间一到就会自动删除对应的键值对。
2.list(列表)
Redis中的list类型的数据存储的是多个有序的字符串,它就相当于Java中的LinkedList。列表中的元素可以是重复的。当列表中的最后一个数据的被弹出之后,该数据结构将会被删除,内存也会被回收。
Redis列表通常用来做异步队列使用,将需要延后处理的任务序列化成字符串塞进Redis的列表,另外一个线程从这个列表中轮询数据进行处理。
右边进左边出:队列,操作如下所示。
右边进右边出:栈,操作如下所示。
3.hash(字典)
Redis中的字典用于保存键值对数据,它类似于Java中的HashMap,内部的实现细节为数组和链表。当发生碰撞时,在碰撞的节点会将元素链接成为元素链表。但是Redis的字典和Java中的HashMap安排还是有区别的,Redis中的字典的key都是string,同时refresh的策略也是不一样的。HashMap的refresh策略是进行全局的reresh,所以当HashMap很大时,refresh的过程将是一个耗时的操作。内部存储结构如下图所示:
常用命令,如下所示:
其他命令如下表所示:
命令 | 作用 |
hsetnx | 设置key对应的HashMap中的field的value,如果不存在则先创建 |
hmset | 批量设置key对应的HashMap中的field的value |
hmget | 批量获取key对应的HashMap中的field的value |
hexits | 测试key对应的HashMap中的field是否存在 |
hincrby | 给key对应的HashMap中的field的value加指定的值 |
hlen | 返回key对应的HashMap中的field的数量 |
hdel | 删除key对应的HashMap中的field |
hkeys | 返回key对应的HashMap中所有的field |
hvals | 返回key对应的HashMap中所有的field的value |
4.set(集合)
Redis 数据结构中的集合相当于 Java 中的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL。与List不同的是set不能出现相同的数据。
常用命令,如下所示:
其他命令如下表所示:
命令 | 作用 |
sdiff | 求给定key对应的set与第一个key对应的set的差集 |
suion | 求给定key对应的set并集 |
sinter | 求给定key对应的set交集 |
srem | 删除key对应的set中的一个元素 |
sdiffstore | 求给定key对应的set与第一个key对应的set的差集,并存储到另一个key对应的set中 |
sinterstore | 求给定key对应的set交集,并存储到另一个key对应的set中 |
suionstore | 求给定key对应的set并集,并存储到另一个key对应的set中 |
somve | 从第一个key对应的set中删除指定元素并添加到第二个key对应的set中 |
scard | 返回key对应的set的元素个数 |
sismember | 测试某个元素是否为key对应的set中的元素个数 |
5.zset(有序集合)
zset 可能是 Redis 提供的最为特色的数据结构,它也是在面试中面试官最爱问的数据结构。它类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,但是相对于无序set来说zset是有有序的,同时保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。它的内部实现用的是一种叫做「跳跃列表」的数据结构。
> zadd books 9.0 "think in java" (integer) 1 > zadd books 8.9 "java concurrency" (integer) 1 > zadd books 8.6 "java cookbook" (integer) 1 > zrange books 0 -1 # 按 score 排序列出,参数区间为排名范围 1) "java cookbook" 2) "java concurrency" 3) "think in java" > zrevrange books 0 -1 # 按 score 逆序列出,参数区间为排名范围 1) "think in java" 2) "java concurrency" 3) "java cookbook" > zcard books # 相当于 count() (integer) 3 > zscore books "java concurrency" # 获取指定 value 的 score "8.9000000000000004" # 内部 score 使用 double 类型进行存储,所以存在小数点精度问题 > zrank books "java concurrency" # 排名 (integer) 1 > zrangebyscore books 0 8.91 # 根据分值区间遍历 zset 1) "java cookbook" 2) "java concurrency" > zrangebyscore books -inf 8.91 withscores # 根据分值区间 (-∞, 8.91] 遍历 zset,同时返回分值。inf 代表 infinite,无穷大的意思。 1) "java cookbook" 2) "8.5999999999999996" 3) "java concurrency" 4) "8.9000000000000004" > zrem books "java concurrency" # 删除 value (integer) 1 > zrange books 0 -1 1) "java cookbook" 2) "think in java"...
zset 内部的排序功能是通过一种叫做跳跃列表的数据结构来实现的,它的结构非常特殊,也比较复杂。因为 zset 要支持随机的插入和删除,所以它不好使用数组来表示。
过期时间
Redis 所有的数据结构都可以设置过期时间,时间到了,Redis 会自动删除相应的对象。需要注意的是过期是以对象为单位,比如一个 hash 结构的过期是整个 hash 对象的过期,而不是其中的某个子 key。
还有一个需要特别注意的地方是如果一个字符串已经设置了过期时间,然后你调用了 set 方法修改了它,它的过期时间会消失。