redis各数据类型使用场景介绍

一、Stringredis

经常使用命令:数据库

除了get、set、incr、decr mget等操做外,Redis还提供了下面一些操做:数组

获取字符串长度服务器

往字符串append内容数据结构

设置和获取字符串的某一段内容并发

设置及获取字符串的某一位(bit)app

批量设置一系列字符串的内容ide


应用场景:网站

String是最经常使用的一种数据类型,普通的key/value存储均可以归为此类,value其实不只是String,spa

也能够是数字:好比想知道何时封锁一个IP地址(访问超过几回)。INCRBY命令让这些变得很容易,经过原子递增保持计数。


实现方式:

m,decr等操做时会转成数值型进行计算,此时redisObject的encoding字段为int。


二、Hash

经常使用命令:

hget,hset,hgetall 等。

应用场景:

咱们简单举个实例来描述下Hash的应用场景,好比咱们要存储一个用户信息对象数据,包含如下信息:

           用户ID,为查找的key,

           存储的value用户对象包含姓名name,年龄age,生日birthday 等信息,

   若是用普通的key/value结构来存储,主要有如下2种存储方式:

       第一种方式将用户ID做为查找key,把其余信息封装成一个对象以序列化的方式存储,

           如:set u001 "李三,18,20010101"

           这种方式的缺点是,增长了序列化/反序列化的开销,而且在须要修改其中一项信息时,须要把整个对象取回,而且修改操做须要对并发进行保护,引入CAS等复杂问题。

       第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称做为惟一标识来取得对应属性的值,

           如:mset user:001:name "李三 "user:001:age18 user:001:birthday "20010101"

           虽然省去了序列化开销和并发问题,可是用户ID为重复存储,若是存在大量这样的数据,内存浪费仍是很是可观的。

    那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,

    并提供了直接存取这个Map成员的接口,

        如:hmset user:001 name "李三" age 18 birthday "20010101"   

            也就是说,Key仍然是用户ID,value是一个Map,这个Map的key是成员的属性名,value是属性值,

            这样对数据的修改和存取均可以直接经过其内部Map的Key(Redis里称内部Map的key为field), 也就是经过 

            key(用户ID) + field(属性标签) 操做对应属性数据了,既不须要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。


这里同时须要注意,Redis提供了接口(hgetall)能够直接取到所有的属性数据,可是若是内部Map的成员不少,那么涉及到遍历整个内部Map的操做,因为Redis单线程模型的缘故,这个遍历操做可能会比较耗时,而另其它客户端的请求彻底不响应,这点须要格外注意。

  实现方式

上面已经说到Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不一样实现,这个Hash的成员比较少时Redis为了节省内存会采用相似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。



三、List

经常使用命令:

    lpush,rpush,lpop,rpop,lrange,BLPOP(阻塞版)等。


应用场景:

    Redis list的应用场景很是多,也是Redis最重要的数据结构之一。

    咱们能够轻松地实现最新消息排行等功能。

    Lists的另外一个应用就是消息队列,能够利用Lists的PUSH操做,将任务存在Lists中,而后工做线程再用POP操做将任务取出进行执行。


实现方式:

    Redis list的实现为一个双向链表,便可以支持反向查找和遍历,更方便操做,不过带来了部分额外的内存开销,Redis内部的不少实现,包括发送缓冲队列等也都是用的这个数据结构。


RPOPLPUSH source destination


    命令 RPOPLPUSH 在一个原子时间内,执行如下两个动做:

    将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。

    将 source 弹出的元素插入到列表 destination ,做为 destination 列表的的头元素。

    若是 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,能够把这种特殊状况视做列表的旋转(rotation)操做。

    一个典型的例子就是服务器的监控程序:它们须要在尽量短的时间内,并行地检查一组网站,确保它们的可访问性。

    redis.lpush "downstream_ips", "192.168.0.10"

    redis.lpush "downstream_ips", "192.168.0.11"

    redis.lpush "downstream_ips", "192.168.0.12"

    redis.lpush "downstream_ips", "192.168.0.13"

    Then:

    next_ip = redis.rpoplpush "downstream_ips", "downstream_ips"


BLPOP


  假设如今有 job 、 command 和 request 三个列表,其中 job 不存在, command 和 request 都持有非空列表。考虑如下命令:

  BLPOP job command request 30  #阻塞30秒,0的话就是无限期阻塞,job列表为空,被跳过,紧接着command 列表的第一个元素被弹出。

  1) "command"                             # 弹出元素所属的列表

  2) "update system..."                    # 弹出元素所属的值 

  为何要阻塞版本的pop呢,主要是为了不轮询。举个简单的例子若是咱们用list来实现一个工做队列。执行任务的thread能够调用阻塞版本的pop去获取任务这样就能够避免轮询去检查是否有任务存在。当任务来时候工做线程能够当即返回,也能够避免轮询带来的延迟。



四、Set

经常使用命令:

    sadd,srem,spop,sdiff ,smembers,sunion 等。


应用场景:

    Redis set对外提供的功能与list相似是一个列表的功能,特殊之处在于set是能够自动排重的,当你须要存储一个列表数据,又不但愿出现重复数据时,set是一个很好的选择,而且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

    好比在微博应用中,每一个人的好友存在一个集合(set)中,这样求两我的的共同好友的操做,可能就只须要用求交集命令便可。

    Redis还为集合提供了求交集、并集、差集等操做,能够很是方便的实


实现方式:

    set 的内部实现是一个 value永远为null的HashMap,实际就是经过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的缘由。


五、Sort Set

经常使用命令:

    zadd,zrange,zrem,zcard等


  使用场景:

    以某个条件为权重,好比按顶的次数排序.

    ZREVRANGE命令能够用来按照得分来获取前100名的用户,ZRANK能够用来获取用户排名,很是直接并且操做容易。

    Redis sorted set的使用场景与set相似,区别是set不是自动有序的,而sorted set能够经过用户额外提供一个优先级(score)的参数来为成员排序,而且是插入有序的,即自动排序。

    好比:twitter 的public timeline能够以发表时间做为score来存储,这样获取时就是自动按时间排好序的。

    好比:全班同窗成绩的SortedSets,value能够是同窗的学号,而score就能够是其考试得分,这样数据插入集合的,就已经进行了自然的排序。

    另外还能够用Sorted Sets来作带权重的队列,好比普通消息的score为1,重要消息的score为2,而后工做线程能够选择按score的倒序来获取工做任务。让重要的任务优先执行。


    须要精准设定过时时间的应用

    好比你能够把上面说到的sorted set的score值设置成过时时间的时间戳,那么就能够简单地经过过时时间排序,定时清除过时数据了,不只是清除Redis中的过时数据,你彻底能够把Redis里这个过时时间当成是对数据库中数据的索引,用Redis来找出哪些数据须要过时删除,而后再精准地从数据库中删除相应的记录。


  实现方式:

    Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是全部的成员,排序依据是HashMap里存的score,使用跳跃表的结构能够得到比较高的查找效率,而且在实现上比较简单。


六、消息订阅Pub/Sub


Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你能够设定对某一个key值进行消息发布及消息订阅,

当一个key值上进行了消息发布后,全部订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用做实时消息系统,好比普通的即时聊天,群聊等功能。


客户端1:subscribe  rain

客户端2:PUBLISH  rain "my love!!!"

(integer) 2 表明有几个客户端订阅了这个消息



 七、Transactions


    谁说NoSQL都不支持事务,虽然Redis的Transactions提供的并非严格的ACID的事务(好比一串用EXEC提交执行的命令,在执行中服务器宕机,那么会有一部分命令执行了,剩下的没执行),可是这个Transactions仍是提供了基本的命令打包执行的功能(在服务器不出问题的状况下,能够保证一连串的命令是顺序在一块儿执行的,中间有会有其它客户端命令插进来执行)。

    Redis还提供了一个Watch功能,你能够对一个key进行Watch,而后再执行Transactions,在这过程当中,若是这个Watched的值进行了修改,那么这个Transactions会发现并拒绝执行。

Session 1

    (1)第1步

    redis 127.0.0.1:6379> get age

    "10"

    redis 127.0.0.1:6379> watch age

    OK

    redis 127.0.0.1:6379> multi

    OK

    redis 127.0.0.1:6379>

 

Session 2

    (2)第2步

    redis 127.0.0.1:6379> set age 30

    OK

    redis 127.0.0.1:6379> get age

    "30"

    redis 127.0.0.1:6379>


Session 1   

    (3)第3步

    redis 127.0.0.1:6379> set age 20

    QUEUED

    redis 127.0.0.1:6379> exec

    (nil)

    redis 127.0.0.1:6379> get age

    "30"

    redis 127.0.0.1:6379>


第一步,Session 1 尚未来得及对age的值进行修改

第二步,Session 2 已经将age的值设为30

第三步,Session 1 但愿将age的值设为20,但结果一执行返回是nil,说明执行失败,以后咱们再取一下age的值是30,这是因为Session   1中对age加了乐观锁致使的。

相关文章
相关标签/搜索