Redis系列----(二)redis中的数据结构类型

一.前言

redis并不是简单的key-value数据容器,不能将其理解为静态存储数据,它是动态交互的数据结构服务器,可以被用作缓存,高性能k-v数据库等。

它支持很多种类型的数据结构,不仅支持string类型的value,还支持很多种复杂类型的数据。以下简单列出redis支持的数据类型,后续再对每种数据类型以及它们的常用操作命令做详细介绍

1.安全二进制氏String类型:将String类型作为元素值;

2.Lists类型:根据插入顺序的String类型为元素的集合,基于Linked List实现,非Array型;

3.Sets类型:无重复且无序的String类型为元素的集合;

4.Sorted Set类型:无重复且有序的String类型为元素的集合;

5.Hashes类型:映射域到值类型的数据结构,其中域和值都是String类型;


二.Redis数据类型详解

在介绍数据类型之前,先让我们来看看Redis k-v数据结构中非常重要的key形式。redis中的key是二进制安全的也就是说任何二进制序列都可以作为key,譬如:字符串“foo”,一张图片的内容等。甚至空字符串都可以。

良好的key的命名规则如下:

1.key不要太长。在redis中可以的最大容量是512M,但是实际中key超过1024byte就非良好的设计方式了。key值太大不仅浪费内存空间,更是在请求中对于key'的查找需要更多的时间进行比较;

2.key值不宜太短。这个原则貌似与第一条相冲突,实则不然。有时key的变长使得增加空间相对于使得key更具可读性更显次要;

3.key的命名中可以使用冒号和破折号加以细分,使key更具可读性,灵活性。例如:aticle:1000:tags。其中第一位表示类型,第二位表示该类型对象的Id,第三位表示Id为1000的文章中的标记;

作用于Key的常用命令:

redis提供很多非常实用而有效的命令,这些命令作用于redis中的Key,管理Key的空间。

1.EXISTS

exists主要是查找指定的键是否存在,如果存在则返回(Integer) 1,否则返回(Integer) 0。使用情况如下:

首先实用redis-cli命令进入redis的客户端命令行模式:

127.0.0.1:6379> SET mystring "mystring0"
OK
127.0.0.1:6379> GET mystring
"mystring0"
127.0.0.1:6379> EXISTS mystring
(integer) 1
127.0.0.1:6379> EXISTS mystring1
(integer) 0
127.0.0.1:6379> 

2.DEL

del主要用来删除Key,并将Key对应的值随之删除。

127.0.0.1:6379> EXISTS mystring
(integer) 1
127.0.0.1:6379> 
127.0.0.1:6379> DEL mystring
(integer) 1
127.0.0.1:6379> EXISTS mystring
(integer) 0
127.0.0.1:6379> GET mystring
(nil)
127.0.0.1:6379> 


3 .EXPIRE

expire设置Key的有效期,如果超过设定的存活时间,Key将自动失效并随之删除。与之相反的命令PERSIST使Key永久有效,与之协作的命令TTL查看Key剩余有效时间。

127.0.0.1:6379> SET mystring1 "string1"
OK
127.0.0.1:6379> EXISTS mystring1
(integer) 1
127.0.0.1:6379> EXPIRE mystring1 10000
(integer) 1
127.0.0.1:6379> GET mystring1
"string1"
127.0.0.1:6379> TTL mystring1
(integer) 9976
127.0.0.1:6379> TTL mystring1
(integer) 9975
127.0.0.1:6379> TTL mystring1

127.0.0.1:6379> 
127.0.0.1:6379> SET mystring2 "string2"
OK
127.0.0.1:6379> EXPIRE mystring2 20
(integer) 1
127.0.0.1:6379> 
127.0.0.1:6379> GET mystring2
"string2"
127.0.0.1:6379> TTL mystring2
(integer) 6
127.0.0.1:6379> TTL mystring2
(integer) 5
127.0.0.1:6379> TTL mystring2
(integer) 2
127.0.0.1:6379> TTL mystring2
(integer) 1
127.0.0.1:6379> GET mystring2
(nil)
127.0.0.1:6379> 


redis中Value的数据类型

  • Sting类型
先让我们来看看String类型吧。String类型是redis中最简单数据类型,String类型实质是一个String映射到另一个String,同时它也是复杂类型的基类型。String类型的value不得超过512M,可以被使用在很多场合,例如:缓存页面。
127.0.0.1:6379> SET mystring7 string7
OK
127.0.0.1:6379> GET mystring7
"string7"
127.0.0.1:6379> SET mystring8 "string8"
OK
127.0.0.1:6379> GET mystring8
"string8"

从以上命令中可以看到GET返回的值是String类型,且SET命令中的value参数可以含有双引号也不含有。SET和GET命令是设置和获取String类型的基本命令,且它们可以附加参数,但这里不加以讨论其命令,在稍后的章节中再详细介绍命令的使用详情。

如果String类型的值是数字类型,则可以使用加法和减法操作,在使用算术运算的时候,其实redis将其String类型解析成Integer类型进行运算的。让我们来看看接下来的例子:

127.0.0.1:6379> SET mystring12 100
OK
127.0.0.1:6379> INCR mystring12
(integer) 101
127.0.0.1:6379> GET mystring12
"101"
127.0.0.1:6379> INCRBY mystring12 35
(integer) 136
127.0.0.1:6379> GET mystring12
"136"
127.0.0.1:6379> DECR mystring12
(integer) 135
127.0.0.1:6379> GET mystring12
"135"
127.0.0.1:6379> DECRBY mystring12 200
(integer) -65
127.0.0.1:6379> GET mystring12
"-65"

String类型非常简单,我们就介绍的这里。以后介绍命令时候再进行补充!

  • Lists类型
Lists类型一般实现有常见的两种:
1.基于Arrays线性数组实现的List数据结构
2.基于Linked List链式节点实现的List数据结构
在每种应用中的实现都是差不多遵循这样的思想,如:java的ArrayList和LinkedList、c语言数据结构的线性链表和链式链表;同样redis中也遵循这样的思想。但是redis中的Lists则采用的是第二种算法。LinkedList的实现决定了它有高性能的插入删除操作,而Arrays型List性能在于查询获取。
因为相对于缓存或者数据库系统而言,在插入或者更新的操作上性能更重要,相对于查询操作,查询所带来的性能损耗更低。平衡性能的确采用Linked List实现更具有优越性。
redis中复合类型的基元素都是String类型。Lists也不例外。Lists类型实质就是一串String元素的序列,redis提供了很多丰富命令,用于操作Lists类型。
1.LPUSH、RPUSH 和 LPOP、RPOP 以及 LRANGE
LPUSH从List左边插入元素,RPUSH从List右边插入元素。LPOP从List左边弹出元素并从List中移除该元素,RPOP从List右边弹出元素并移除。这种操作元素的特点很类似双向队列的实现。所以可以用List类型来作为队列使用,使其用于线程交互。LRANGE是获取List中的范围元素。接下来就让我们看看这些命令如何使用:

127.0.0.1:6379> LPUSH mylist0 name age address phoneNo
(integer) 4
127.0.0.1:6379> RPUSH mylist1 name age address phoneNo
(integer) 4
127.0.0.1:6379> LRANGE mylist0 0 -1
1) "phoneNo"
2) "address"
3) "age"
4) "name"
127.0.0.1:6379> LRANGE mylist1 0 -1
1) "name"
2) "age"
3) "address"
4) "phoneNo"

其中LRANGE中的第二个参数表示要查找元素的起始位,第三个元素表示结束位(若为负数,表示从List尾部开始计数。例如:-1表示倒数第一位,-2表示倒数第二位),其中mylist0和mylist1元素位置刚好相反。

127.0.0.1:6379> RPOP mylist1
"phoneNo"
127.0.0.1:6379> RPOP mylist1
"address"
127.0.0.1:6379> RPOP mylist1
"age"
127.0.0.1:6379> RPOP mylist1
"name"
127.0.0.1:6379> RPOP mylist1
(nil)

RPOP命令使得mylist1一直从右边弹出新的元素,并且移除。直到元素为空。
这里需要注意:

127.0.0.1:6379> EXISTS mylist1
(integer) 0

这时发现mylist1键已经不存在。redis提供了非常棒的功能:自动创建或者移除Key。意思是说,不需要预先创建值为空的Key,在向指定的Key中存入元素的时候如果发现Key不存在就自动创建Key。同理,也不需要删除元素为空的键,在复杂类型中如果元素为空,则Key将会被自动删除。这样可以保证更有效的利用Key空间!

在前面提到List可以用于线程之间的交互通信,这里我们简单的说下List的适用场景:
1.List的PUSH和POP特点决定其可以被用作为队列使用;
2.List的特点1决定了其具有记忆功能,可以保存最近的操作,并快速获取;
3.List的特点1决定了其可被应用于Product/Consumer模式(生产者/消费者模式),生产者放入元素,消费者获取并消费;

Blocking on List

Redis在List的基础上还提供了Blocking List(阻塞式List),这种List非常类似于Java中的阻塞队列。采用信号量机制,和Java中的object的wait和notify、condition的信号量实现非常相似。正常情况下的List如果获取元素没有则返回客户端为null,但是Blocking on List如果获取元素为空,则不返回,此时阻塞客户端请求,直到有值时才返回,或者可以设置超时时间,超过设定时间则返回;
Redis实现命令BRPOP、BLPOP达到阻塞式List,如果List为空,则不返回客户端陷入等待直达有新的元素加入List才返回或者到达指定的超时时间。
127.0.0.1:6379> 
127.0.0.1:6379> 
127.0.0.1:6379> BRPOP mylist 10000




如上使用BRPOP命令,则客户端阻塞等待。第二个参数是超时时间,如果为0表示一直等待。再打开一个redis-cli命令窗口,向mylist中添加新的元素:
127.0.0.1:6379> LPUSH mylist lxy
(integer) 1
127.0.0.1:6379> 

则等待的客户端得到通知,返回新的元素:
127.0.0.1:6379> BRPOP mylist 10000





1) "mylist"
2) "lxy"
(218.69s)
127.0.0.1:6379> 
因为BRPOP可以等待多个List,所以返回时候同时返回List名的元素。第三个参数为已等待时间。

对于Blocking List还有一些规则如下:

A few things to note about BRPOP:

  1. Clients are served in an ordered way: the first client that blocked waiting for a list, is served first when an element is pushed by some other client, and so forth.
  2. The return value is different compared to RPOP: it is a two-element array since it also includes the name of the key, because BRPOP and BLPOP are able to block waiting for elements from multiple lists.
  3. If the timeout is reached, NULL is returned.

  • Sets类型
Set类型是无序且无重复的String元素的集合。redis也提供了大量对于Sets类型的操作,比如:交集、并集、补集在多个Set之间;测试给定元素是否存在等。
1.SADD
sadd命令主要向Set中插入新的元素,如果有则覆盖,其中可以接多个参数作为插入的元素。
127.0.0.1:6379> SADD myset 0 0 1 2 3 4 5 6 6 6 7 8 8
(integer) 9
从上可以看出,虽然有很多重复元素,但是直插入了9个元素。

2.SISMEMBER
sismember只要测试指定元素在Set中是否存在,如果存在则返回1,否则返回0
127.0.0.1:6379> SISMEMBER myset 0
(integer) 1
127.0.0.1:6379> SISMEMBER myset 9
(integer) 0
127.0.0.1:6379> SISMEMBER myset 7
(integer) 1
127.0.0.1:6379> 

3.SMEBERS
smembers获取Set中的所有元素,并且是无序的
127.0.0.1:6379> SMEMBERS myset
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
127.0.0.1:6379> 

4.SINTER
sinter用于取多个Set的交集
此外还有很多有关Set的操作命令,但在这里我们主要以讨论数据结构为主,对命令不做详细讲解。在稍后的redis系列中会专门有一节关于常用命令的介绍。

  • Sorted Set类型
Sorted Set类型是有序的Set类型,有点像Hashes和Set的混合型数据结构。具有Set的唯一无重复特性,且有序的实现是通过额外的浮点值被称作为score决定,与Hashes的Key有点相似。
Sorted Set的排序规则,假设有两个元素a、b
1.如果a.score > b.score,则a > b;
2.如果a.score = b.score,a > b,则a > b;
1.ZADD
zadd向Sorted Set中插入元素
127.0.0.1:6379> ZADD mysortset 1 "BACD"
(integer) 1
127.0.0.1:6379> ZADD mysortset 2 "ABCD"
(integer) 0
127.0.0.1:6379> ZADD mysortset 2 "BCDE"
(integer) 1
zadd中1,2,2就是这个元素的score,根据score进行排序元素。
2.ZRANGE、ZREVRANGE
zrang获取Sorted Set中的元素,ZREVRANGE获取Sorted Set中元素并方向输出。
127.0.0.1:6379> ZRANGE mysortset 0 -1
1) "BACD"
2) "ABCD"
3) "BCDE"
127.0.0.1:6379> 
127.0.0.1:6379> ZREVRANGE mysortset 0 -1
1) "BCDE"
2) "ABCD"
3) "BACD"
127.0.0.1:6379>
以上后去元素还可以携带参数,输出score
127.0.0.1:6379> ZRANGE mysortset 0 -1 withscores
1) "BACD"
2) "1"
3) "ABCD"
4) "2"
5) "BCDE"
6) "2"
127.0.0.1:6379> 

Sorted Set不仅仅以上的功能,它还提供了在范围上的操作:
1.ZRANGBYSCORE
zrangbyscore根据score获取输出元素, -inf参数表明获取小于指定score的元素
127.0.0.1:6379> ZRANGEBYSCORE mysortset -inf 4 withscores
1) "BACD"
2) "1"
3) "ABCD"
4) "2"
5) "BCDE"
6) "2"
127.0.0.1:6379>

2.ZREMRANGBYSCORE
zremrangbyscore获取指定score范围内的元素个数
127.0.0.1:6379> ZREMRANGEBYSCORE mysortset 2 6
(integer) 3
127.0.0.1:6379> 
以上只是Sorted Set的简单命令使用,对于复杂的命令将在后续章节中详细介绍,这里只讨论数据类型

  • Hashes类型

redis中的Hashes类型类似Java中map,key-value键值对映射型数据结构。redis提供了很多命令用于操作Hashes。

1.HMSET

hmset用于向Hashes中插入元素,插入元素的规则如下:

127.0.0.1:6379> HMSET usr:1000 username lxy birth 1991 verified 1
OK
127.0.0.1:6379>

2.HMGET、HGET

hmge和HGET都是用于获取Hashes中的元素,规则如下:

127.0.0.1:6379> HMGET usr:1000 username birth verified
1) "lxy"
2) "1991"
3) "1"
127.0.0.1:6379> 	

127.0.0.1:6379> HGET usr:1000 username birth
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> 
127.0.0.1:6379> HGET usr:1000 username
"lxy"
127.0.0.1:6379> 
从以上的使用情况可以看出,HMGET是同时获取Hashes中的多个Key的值,而HGET一次只能获取一个!


如发现文章中有错误的地方,希望广大读者们及时与我沟通,帮我纠正错误,谢谢各位的支持!

本篇文章参考:

An introduction to Redis data types and abstractions:http://redis.io/topics/data-types-intro


你可能感兴趣的:(Redis系列)