- 命令参考:http://redisdoc.com/
- 默认端口:6379
redis有5个基本数据结构:
redis的所有数据结构都是以唯一的KEY值来获取相应的value数据,不同类型的数据结构的差异在于value的结构不一样。
string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)
String(字符串)
字符串的结构使用非常广泛,常用于缓存用户信息,我们将用户信息结构体使用JSON序列化成字符串,然后将序列化后的字符串塞进Redis来缓存,同样,取用户信息会经过一次反序列化的过程。
redis的字符串是动态字符串,是可以修改的字符串,内部结构类似于java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,如图:内部为当前的字符串实际分配的空间大小( capacity)一般要高于实际字符串的长度len。当字符串长度<1M时,扩容都是加倍现有空间,如果>1M,扩容时一次只会多扩1M的空间,需要注意的是字符串最大长度为512M。
操作 | 命令 | 结果 |
创建字符串 | set key value | 成功返回ok |
获得字符串 | get key | 存在返回value,不存在返回(nil) |
检查key 是否存在 | exists key | 存在返回1,不存在返回0 |
删除字符串 | del key | 删除成功返回1,失败返回0 |
批量对多个字符串进行读写 | mget key1 key2 key3... | 返回一个列表 |
批量新增多个字符串 | mset key1 value1 key2 value2 key3 value3 | 成功返回ok |
设置过期时间 | setex key 过期时间(秒) value | key存在,覆写旧值 |
将 | setnx key value | 若给定的 |
整数类型的value,自增 | 自增1:incr key 自增固定值:incrby key 值 | 自增范围:signed long 的最大最小值,超过了这个值,Redis 会报错 |
补充:字符串是由多个字节组成,每个字节又是由 8 个 bit 组成,如此便可以将一个字符串看成很多 bit 的组合
list (列表)
redis的列表相当于Java里的LinkedList,是链表,在java中,在批量add的时候,会先转换为数组;数组是用于储存多个相同类型数据的集合,但是在redis中,不是数组;链式结构意味着list的插入和删除操作快,只需要修改链表节点指针;但是索引定位比较慢。
redis的底层并不是一个简单的linkedList,而是quickList的一个快速链表结构;在列表元素较少的情况下会使用一块连续的内存存储,这个结构是zipList,也就是压缩列表。他将所有的元素紧挨着一起存储,分配的是一块连续的内存,当数据量较多的情况才会改成quickList。因为普通的链表需要附加的指针空间太大,比较浪费空间,而且会加重内存的碎片化。
redis的列表结构常用于异步队列,将需要延后处理的任务结构体序列化为字符串塞进redis的列表,另一个线程从这个列表中轮询数据进行处理。
操作 | 命令 | 结果 |
将一个或多个value插入到列表key的表尾(最右边) | rpush key value1 value2 value3... | key 不存在时,创建新的列表 key存在但不是列表时,报错 |
返回列表长度 | llen key | 返回列表长度,列表不存在时,返回0 |
移除并返回列表key的头元素(队列) | lpop key | 返回删除旧的列表头的新的列表头 |
移除并返回列表key的尾元素(栈) | rpop key | 返回删除旧的列表头的新的列表头 |
返回列表key中,下标为index的元素 | lindex key index | 返回对应下标的值(index可以为负数,从末尾取值);性能随着index的增大而变差 |
获取指定区间的key的元素 | lrange key start stop | 返回列表区间内的值,下标越界时,返回(empty list or set) |
保留区间内的元素,其余删除 | ltrim key start stop | 成功返回ok;保留start和stop |
拓展--队列和栈:
| | 队列 | 栈 |
不同 | 删除位置 | 表头 | 表尾 |
应用场景 | 资源管理、消息缓冲等 | 函数调用、递归等 | |
数据进出 | 右进左出 | 右进右出 | |
空间共享 | 无法实现 | 顺序栈可以实现 | |
相同 | 结构 | 线性结构 | |
数据插入 | 表尾插入 | ||
实现方式 | 可以通过顺序结构和链式结构实现 | ||
复杂程度 | 删除、插入的时间复杂度和空间复杂度相同 | ||
管理模式 | 多链栈和多链队列的管理模式可以相同 |
hash (字典)
redis的字典相当于java的HashMap,无序字典,内部实现结构上同java的HashMap也是一致的,不同的是redis的字典值只能是字符串,另外他们的rehash(重新整理)的方式不一样,java中的HashMap在字典很大时,rehash是个耗时的操作,需要一次全部rehash,redis为了提高性能,不堵塞服务,所以采用了渐进式rehash策略。渐进式rehash会在rehash的同时,保留新旧两个hash结构,查询时会同时查询两个hash结构,然后在后续的定时任务以及hash操作指令中,循序渐进的将旧hash内容逐渐迁移到新的hash结构中,当搬迁完成,就会用新的hash结构取代。
当 hash 移除了最后一个元素之后,该数据结构自动被删除,内存被回收。
hash结构的存储消耗要高于单个字符串。
操作 | 命令 | 结果 |
将哈希表key中的域field的值设置为value | hset key field value | field 不存在时,创建新的域,返回1 field 存在,覆盖旧值,返回0 命令行的字符串如果包含空格,要用引号括起来 |
返回哈希表 | hgetall key | |
获得哈希表key中域的数量 | hlen key | |
返回哈希表中key中给定域field的值 | hget key field | |
返回哈希表 | hmget key field1 field2 | |
同时将多个 | hmset key field1 value1 field2 value3 | |
为哈希表 | hincrby key field value | key不存在的情况下会新增一个 |
127.0.0.1:6379> hset books java "think in java"
(integer) 1
127.0.0.1:6379> hset books c "thik in c"
(integer) 1
127.0.0.1:6379> hset books java "123"
(integer) 0
127.0.0.1:6379> hgetall books
1) "java"
2) "123"
3) "c"
4) "thik in c"
127.0.0.1:6379> hlen books
(integer) 2
127.0.0.1:6379> hmget books java
1) "123"
127.0.0.1:6379> hmset books java "11233" python "2233"
OK
127.0.0.1:6379> hmget books java python
1) "11233"
2) "2233"
127.0.0.1:6379> hincrby user age 1
(integer) 1
set (集合)
redis的集合相当于java里的HashSet,内部的键值对是无序且唯一的。redis的集合是通过哈希表实现的,所以添加、删除、查询的复杂度都是 O(1), 每个集合可以存放40多亿个成员。当删除集合中的最后一个元素后,数据结构自动删除,内存被回收。
操作 | 命令 | 结果 |
将一个或多个member(元素)加入到集合key中,已存在于集合的元素将被忽略 | sadd key value/value1 value2... | value存在时,添加元素返回0, value不存在,返回1 |
移除并返回集合中的一个随机元素 | spop key | 返回移除的元素 |
返回集合中的元素 | srandmember key [count] | count不存在,随机返回一个元素 当count存在: 1.count为正数,count 小于集合基数 ,返 回count个不同元素 2.count为正数,count大于集合的基数,返回整个集合 3.count为负数,返回一个数组,并且数组的元素可能重复出现多次,数组长度为count的绝对值个 |
返回集合所有元素 | smembers key | key存在时,返回集合所有元素 key不存在,返回(empty list or set) |
某元素是否存在 | sismember key value | 存在返回1,不存在返回0 |
获得集合长度 | scard key | 返回集合长度,集合不存在时,返回0 |
zset (有序集合)
zset类似于 Java 的 SortedSet 和 HashMap 的结合体,元素是唯一的不可重复的,它可以给每个 value 赋予一个 double类型的score,代表这个 value 的排序权重,它是有序的,通过权重将元素从小到大排序(元素的score可以相同)。它的内部实现用的是一种叫做「跳跃列表」的数据结构。集合中最后一个 value 被移除后,数据结构自动删除,内存被回收。
操作 | 命令 | 结果 |
将一个或多个元素添加到集合中 | zadd key score value/score1 value1 score2 value2... | 元素不存在,添加元素返回添加元素的个数, 元素存在,返回0,若score值变化,将元素更新到新的score值 score可以为0或者是负数 |
获取范围内的元素 正序 | zrange key start stop | 返回范围内的集合元素,从小到大排列(score相同的成员按照字典顺序排列) 0:第一个; -1:最后一个 start>stop返回:(empty list or set) stop>长度返回:全部集合元素 |
获取范围内的元素 倒序 | zrevrange key start stop | 返回范围内的集合元素,从大到小排列(score相同的成员按照字典逆序排列) 0:第一个; -1:最后一个 start>stop返回:(empty list or set) stop>长度返回:全部集合元素 |
获取集合长度 | zcard key | 返回集合长度,集合不存在时,返回0 |
获取指定value的score | zscore key value | 存在返回value的score,不存在返回nil |
获取value的集合下标 正序 | zrank key value | 返回集合从小到大排序的元素下标,元素不存在时,返回nil |
获取value的集合下标 倒序 | zrevrank key value | 返回集合从大到小排序的元素下标,元素不存在时,返回nil |
返回集合key中,min<= score<=max之间的数据,成员按照score顺序排列 | zrangebyscore key min max [withscores] [limit offset count] | 相同score的值按照字典顺序排列 可选参数: 1.withscores 返回value和score: 1)“value” 2) "score" .... 2.limit 用法同java 注:inf 意思是无穷大 zrangebyscore key -inf inf |
删除元素 | zrem key value | 元素存删除返回1 元素不存在返回0 |
综合:
容器型数据结构的通用规则
list/set/hash/zset 这四种数据结构是容器型数据结构,它们共享下面两条通用规则:
1.create if not exists
如果容器不存在,那就创建一个,再进行操作。比如 rpush 操作刚开始是没有列表的,Redis 就会自动创建一个,然后再 rpush 进去新元素。
2.drop if no elements
如果容器里元素没有了,那么立即删除元素,释放内存。这意味着 lpop 操作到最后一个元素,列表就消失了。
过期时间
Redis 所有的数据结构都可以设置过期时间,时间到了,Redis 会自动删除相应的对象。需要注意的是过期是以对象为单位,比如一个 hash 结构的过期是整个 hash 对象的过期,而不是其中的某个子 key。 还有一个需要特别注意的地方是如果一个字符串已经设置了过期时间,然后你调用了 set 方法修改了它,或者删除了它,它的过期时间会消失。
操作 | 命令 | 结果 |
为给定 | expire key seconds | 已设置过期时间的key 会更新过期时间 |
以秒为单位,返回给定 | ttl key | 当 当 否则,以秒为单位,返回 |