Redis学习笔记:Redis五种常用数据类型及其基本操作
NoSQL=not only SQL:意为“不仅仅是SQL”,泛指非关系型数据库。NoSQL不依赖业务逻辑方式存储而是以简单key-value模式存储。因此大大增加了数据库的扩展能力。Redis是一个开源的key-value存储系统。Redis支持存储的value类型有很多。string(字符串)、list(链表)、set(集合)、zset(sorted set–有序集合)、hash(哈希类型)这
Redis学习笔记(一)
1,NoSQL数据库简介
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。
-
一个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跳跃表
更多推荐
所有评论(0)