Redis学习笔记(一)
- 1,NoSQL数据库简介
- 2,Redis概述
- 3,Redis相关知识介绍
- 4,key的基本操作
- 5,Redis常用数据类型---字符串(String)
- 5.1,String类型简介
- 5.2,String的常用命令
- 5.3,Redis中String的数据结构
- 6,Redis常用数据类型---列表(List)
- 6.1,List类型简介
- 6.2,List的常用命令
- 6.3,Redis中List的数据结构
- 7,Redis常用数据类型---集合(Set)
- 7.1,Set类型简介
- 7.2,Set的常用命令
- 7.3,Redis中Set的数据结构
- 8,Redis常用数据类型---哈希(Hash)
- 8.1,Hash类型简介
- 8.2,Hash的常用命令
- 8.3,Redis中Hash的数据结构
- 9,Redis常用数据类型---Zset
- 9.1,Zset简介
- 9.2,Zset的常用命令
- 9.3,Redis中Zset的数据结构
1,NoSQL数据库简介
- NoSQL=not only SQL:意为“不仅仅是SQL”,泛指非关系型数据库。
- NoSQL不依赖业务逻辑方式存储而是以简单
key-value模式存储。因此大大增加了数据库的扩展能力。
2,Redis概述

- Redis是一个
开源的key-value存储系统。 - Redis支持存储的value类型有很多。包括:string(字符串)、list(链表)、set(集合)、zset(sorted set–有序集合)、hash(哈希类型)
- 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是
原子性的。 - 在此基础上,Redis支持各种不同方式的
排序 - 为了保证效率,数据都是缓存在内存中
- Redis会
周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。 - 并且在以上基础上实现了
master-slave(主从)同步
看不懂没关系,下面进入相关内容的具体介绍
3,Redis相关知识介绍
Redis中默认有16个数据库,类似数组(下标从0开始),初始默认使用0号库。统一密码管理,所有库同样密码。
- /usr/local/bin/redis-cli :使用客户端连接服务器上的Redis。如下图:
- 使用命令
select <dbid>来切换数据库。如下图: - 使用命令desize查看当前数据库的key数量(初始为0),如下图:
- flushdb清空当前库,如下图:
- flushall通杀全部库,慎用!!!
Redis较memcached的优点:
- memcached支持的数据类型比较单一,Redis不仅仅支持简单的k/v 类型的数据,同时还提供list,set,zset,hash等数据结构的存储;而memcached 只支持简单数据类型,需要客户端自己处理复杂对象。
- memcached不支持持久化操作,仅允许在内存中存储;Redis既可以在内存中存储还可以进行持久化操作。
- memcached中使用多线程加锁常规技术;Redis使用单线程加多路IO复用技术,效果更好,可以充分让CPU发挥效能。
举例说明单线程和多路IO复用技术思想,如下图:

4,key的基本操作
- keys *:查看当前库中所有的key
- exists key:判断某个key是否存在
- type key :查看你的key是什么类型
- del key:删除指定的key数据
- unlink key:根据value选择非阻塞删除
- 注意:del 和 unlink都是删除,但二者是有区别的:
del的删除是删除指定的key数据;
unlink的删除是仅将keys从keyspace元数据中删除(真正的删除会在后续异步操作) - expire key 10:为给定的key设置过期时间为10秒钟
- ttl key :查看还有多少秒过期,-1表示永不过期,-2表示已过期








5,Redis常用数据类型—字符串(String)
特别说明一点:我们所说的Redis数据类型指的是存到**value**中的数据类型。
5.1,String类型简介
- String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
- String类型是
二进制安全的。只要内容可以使用字符串表示就可以存储到string中。比如jpg图片或者序列化的对象。 - 一个Redis中字符串value最多可以是512M
5.2,String的常用命令
- set key value:添加键值对
- get key:查询key对应的键值
- 注意:如果设置了两次相同的key,后设置的就会把之前的key覆盖掉。如下图:
- append key value:将给定的value追加到原值的末尾
- strlen key:获得值的长度
- setnx key value:只有在key 不存在时 ,才能设置 key 的值
- incr key:将 key 中储存的数字值增1(只能对数字值操作,如果为空,新增值为1)
- decr key:将 key 中储存的数字值减1(只能对数字值操作,如果为空,新增值为-1)
- incrby / decrby key 步长:通过自定义步长方式增减 key 中储存的数字值
- mset key1 value1 key2 value2 …:同时设置一个或多个键值对
- mget key1 key2 key3 …:同时获取一个或多个value
- msetnx key1 value1 key2 value2 …:所有给定 key 都不存在时,同时设置一个或多个 key-value 对
注意:此操作有原子性,只要有一个不符合条件的key。其他的也都不能设置成功。,如下图: - getrange key 起始位置 结束位置:获得值的范围,类似java中的substring
- setrange key 起始位置 value:用 value覆写key所储存的字符串值,从起始位置开始(索引从0开始)
- setex key 过期时间 value:可以在设置键值的同时,设置过期时间,单位秒(前面的expire是给已有的键值设置过期时间,注意区别)
- getset key value:以新换旧,设置了新值同时获得旧值














5.3,Redis中String的数据结构
String的数据结构为简单动态字符串。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。

如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间;如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M!!!
6,Redis常用数据类型—列表(List)
6.1,List类型简介
- List中单键多值,即
一个key对应多个value,其中的多个value值使用List进行存储。 - Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
- 它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

6.2,List的常用命令
- lpush / rpush key value1 value2 value3 … :从左边/右边插入一个或多个值(l代表left,r代表right)。如下图:
- lrange key start stop:按照索引下标获得元素(从左到右)
其中lrange k1 0 -1表示取出k1中全部value值(0表示左边第一个,-1代表右边第一个)。如下图: - lpop / rpop key:从左边/右边吐出一个值。值在键在,值光键亡。
pop表示把值拿出来。 - 从左边取出k1的一个value值。如下图:
- 从右边取出k2的一个value值。如下图:
- value值全部取完的时候,key就没有了。如下图:
- rpoplpush key1 key2:从key1列表右边吐出一个值,插到key2列表左边
- lindex key index:按照索引下标获得元素(从左到右)
- llen key:获得列表长度
- linsert key before value newvalue :在value的前面插入newvalue插入值
- lrem key n value:从开始删除n个value(从左到右)
- lset key index value:将列表key下标为index的值替换成value














6.3,Redis中List的数据结构
- List的数据结构为快速链表quickList。
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。
它将所有的元素紧挨着一起存储,分配的是一块连续的内存。
当数据量比较多的时候才会改成quicklist。
因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
7,Redis常用数据类型—集合(Set)
7.1,Set类型简介
- Redis中set对外提供的功能与list类似,是一个列表的功能,
特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。 - Redis的Set是string类型的无序,不可重复集合。
Set底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。
7.2,Set的常用命令
Set集合由一个或多个member构成。
- sadd key value1 value2 …:将一个或多个 member 元素加入到key对应的集合中,已经存在的 member 元素将被忽略
- smembers key:取出key对应的集合中的所有值。
- sismember key value:判断集合是否为含有该value值。1表示有,0表示没有
- scard key:返回key对应集合中的元素个数
- srem key value1 value2…: 删除key对应的集合中的某些元素
- spop key:随机从key对应的集合中吐出一个值
- srandmember key n:
随机从key对应的集合中取出n个值。不会从集合中删除 (rand即为random) - smove sourceKey destinationKey value:把集合中一个值从一个集合移动到另一个集合
- sinter key1 key2:返回两个集合的交集元素
- sunion key1 key2:返回两个集合的并集元素
- sdiff key1 key2:返回两个集合的差集元素(key1中的,不包含key2中的)









7.3,Redis中Set的数据结构
Set数据结构是dict字典,字典是用哈希表实现的(通过哈希表能够快速找到元素)。
Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。 Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
8,Redis常用数据类型—哈希(Hash)
8.1,Hash类型简介
试想场景:
有一个对象user,其中 {id=1,name=zhangsan,age=20}
如果想要把此对象存到Redis中去,该如何存储?
第一种方案:
- 把此对象变为json字符串或将其进行序列化。
- 然后key即为user
- value即为字符串: {id=1,name=zhangsan,age=20}
此方案是最容易想到的一种方案,但存在致命缺点:修改更新数据的时候过于繁琐。
比如:每一年过去之后,age属性都需要加1。这时就需要把数据都取出去,反序列化变为对象,通过对象把值加1,再转化为json存入Redis。这就很繁琐。
于是产生了第二种方案。
第二种方案:
- key可以设置为user:id,value设置为1
- key设置为user:name,value设置为jack
- key设置为user:age,value设置为20
此方案把数据拆开,如果需要修改age,直接取age相关的元素进行操作即可。但也有一个致命的缺点:这样存储数据过于分散,如果一个user中有几十个字段或几百个字段,需要存储很多次。
最终引出了第三种方案。
第三种方案:(使用Hash数据类型进行存储性能较好)
存储值和取值、改值都比较方便

- Redis的hash 是一个键值对集合
- Redis中hash是一个string类型的field和value的映射表
- hash特别适合用于存储对象。类似Java里面的Map<String,Object>
8.2,Hash的常用命令
- hset key field value:给key集合中的 field 键赋值value
- hget key1 field:从key1集合field取出 value
- hmset key1 field1 value1 field2 value2… :批量设置hash的值(一次性设置多个数据值)
- hexists key1 field:查看哈希表 key 中,给定域 field 是否存在。
- hkeys key:列出该hash集合的所有field
- hvals key:列出该hash集合的所有value
- hincrby key field increment:为哈希表 key 中的域 field 的值加上增量
- hsetnx key field value:将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在








8.3,Redis中Hash的数据结构
Hash类型对应的数据结构是两种:ziplist(压缩列表)、hashtable(哈希表)。
当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
9,Redis常用数据类型—Zset
9.1,Zset简介
- Redis有序集合zset与普通集合set非常相似,是一个
没有重复元素的字符串集合。 - 和set不同之处是:
zset有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。 - 集合的成员是唯一的,但是评分可以是重复了 。 因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。
- 访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。
9.2,Zset的常用命令
- zadd key score1 value1 score2 value2…:将一个或多个 member 元素及其 score 值加入到有序集 key 当中
- zrange key start stop (withscores):返回有序集 key 中,下标在start和stop之间的元素。(带withscores,可以让分数一起和值返回到结果集)。
zrange rank 0 -1 (withscores):表示取出全部元素,从小到大排列。如下图: - zrangebyscore key min max (withscores):返回有序集 key 中所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列
- zrevrangebyscore key max min (withscores):同上,改为从大到小排列(其中rev表示reverse)
- zincrby key increment value:为元素的score加上增量
- zrem key value:删除该集合下,指定值的元素
- zcount key min max:统计该集合,分数区间内的元素个数
- zrank key value:返回该值在集合中的排名。(排在第一位的是0)








9.3,Redis中Zset的数据结构
zset是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map<String, Double>(其中Double可以对应评分score),可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。
zset底层使用了两个数据结构:
(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。(hash中的field即为zset中的value值,hash中的value即为zset中的score)

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。
有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。
对于有序集合的底层实现,可以用数组、平衡树、链表等。
- 数组不便元素的插入、删除;
- 平衡树或红黑树虽然效率高但结构复杂;
- 链表查询需要遍历所有效率低。
因此Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。
关于跳跃表的具体知识可以移步至: Redis跳跃表
















