key-value
模式存储。因此大大增加了数据库的扩展能力。开源
的key-value
存储系统。原子性
的。排序
周期性
的把更新的数据写入磁盘
或者把修改操作写入追加的记录文件。master-slave(主从)同步
看不懂没关系,下面进入相关内容的具体介绍
Redis中默认有16个数据库,类似数组(下标从0开始),初始默认使用0号库。统一密码管理,所有库同样密码。
select 来切换数据库
。如下图:Redis较memcached的优点:
举例说明单线程和多路IO复用技术思想,如下图:
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表示已过期
特别说明一点:我们所说的Redis数据类型指的是存到**value**中的数据类型。
String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
String类型是二进制安全
的。只要内容可以使用字符串表示就可以存储到string中。比如jpg图片或者序列化的对象。
一个Redis中字符串value最多可以是512M
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:以新换旧,设置了新值同时获得旧值
String的数据结构为简单动态字符串。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间;如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M!!!
List中单键多值,即一个key对应多个value,其中的多个value值使用List进行存储
。
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
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
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。
它将所有的元素紧挨着一起存储,分配的是一块连续的内存。
当数据量比较多的时候才会改成quicklist。
因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。
Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
Redis中set对外提供的功能与list类似,是一个列表的功能,特殊之处在于set是可以自动排重
的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
Redis的Set是string类型的无序,不可重复集合。Set底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。
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中的)
Set数据结构是dict字典,字典是用哈希表实现的(通过哈希表能够快速找到元素)。
Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。 Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
试想场景:
有一个对象user,其中 {id=1,name=zhangsan,age=20}
如果想要把此对象存到Redis中去,该如何存储?
第一种方案:
此方案是最容易想到的一种方案,但存在致命缺点:修改更新数据的时候过于繁琐。
比如:每一年过去之后,age属性都需要加1。这时就需要把数据都取出去,反序列化变为对象,通过对象把值加1,再转化为json存入Redis。这就很繁琐。
于是产生了第二种方案。
第二种方案:
此方案把数据拆开,如果需要修改age,直接取age相关的元素进行操作即可。但也有一个致命的缺点:这样存储数据过于分散,如果一个user中有几十个字段或几百个字段,需要存储很多次。
最终引出了第三种方案。
第三种方案:(使用Hash数据类型进行存储性能较好)
存储值和取值、改值都比较方便
Redis的hash 是一个键值对集合
Redis中hash是一个string类型的field和value的映射表
hash特别适合用于存储对象。类似Java里面的Map
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 不存在
Hash类型对应的数据结构是两种:ziplist(压缩列表)、hashtable(哈希表)。
当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
没有重复元素的字符串集合。
zset有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。
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)
zset是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map
(其中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跳跃表