轻松学习redis——第一篇

前言:

  学习本是快乐的事情!!想必大家,经常在学习的时候,看到很多很难理解的概念,很多初学者都无法摸透,看完之后又忘记了。这种学习方式太不快乐了。

  所以,今天,我想用一种轻松的方式,跟大伙们一起来学习redis。我会在抽象的概念中,举例子,把概念形象生动的描绘出来。让读者们轻松阅读,轻松学习。

  let's go!!

正文:

1.首先给大伙提供一下,官方文档,

英文文档:https://redis.io/

中文文档:http://www.redis.cn/commands.html

我们要学会去观看文档。最好是英文文档。

官网中简单的描述了,redis是个啥东西:

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.

翻译过来就是:

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting), LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

 

好了,概念很生硬。我们就理解成,redis是一个支持多数据结构类型,效率极高的存储系统即可。那么接下来就去分析这句话。

还有,在这里,我们需要先在linux操作系统中安装一下redis。可以去这里(https://www.cnblogs.com/takeyblogs/p/14316098.html)照着安装一下。

 

2.我们来看看,redis支持存储的5种类型的数据结构,看下图:

 

 

 

 

(1)第一种是,string类型。

  先介绍一下,字符串结构常用的操作:

    SET key value    //存入字符串键值对

    MSET key value [key value...]   //批量存储字符串键值对

    SETNX key value    //存入一个不存在的字符串键值对

    GET key       //获取一个字符串键值

    MGET key [key...]    //批量获取字符串键值

    DEL key [key...]    //删除一个键

    EXPIRE key seconds   //设置一个键的过期时间(秒)

  原子加减:

    INCR key    //将key中存储的数字值加1

    DECR key    //将key中存储的数字值减1

    INCRBY key increment  //将key所存储的值加上increment

    DECRBY key decrement  //将key所存储的值减去decrement

这个枯燥的指令是必须要记住的,因为这基础。接下来,我来举例子说明一下string数据结构的应用场景:

当我们对数据库查询比较频繁的时候,我们可以用redis缓存,将数据存储在缓存中,来提高查询的效率。因为查询数据库,IO操作的效率远低于redis缓存查询的效率。

如果有一个表:

 

 

 (1)单值存在,我们可以利用string数据结构的set操作:SET key value

    将name当作key,balance当作value,即 :

    SET zhuge 1888

    SET yangguo 16000

    。。。

        我们可以通过 GET key,来获取set入的值:

    GET zhuge

    我们就可以获取到1888 这个值。

  这是string最常用,也是最基础的一个使用方式了。

 

(2)我们可以用来做简单的分布式锁:

  SETNX product:10001 true   //返回1代表获取锁成功

   SETNX product:10001 true   //返回0代表获取锁失败

  。。。执行业务操作

  DEL product:10001      //执行完业务后释放锁

  SET prodoct:10001 true ex 10 nx    //防止程序意外终止导致死锁。给key值设置一个时间

  

说明:例如有一个请求,先设置锁成功了,那么另一个请求就无法再设置锁,直到等待第一个请求结束去删除掉锁的时候,其他请求才可以去设置锁。

(3)计数器:我们微信观看公众号推文的时候,文章末尾总会出现一个计数器,来展示该文章有多少人看过,如图:

 

 

 

  那么我们可以用redis来实现这个功能:

  INCR article:readcount:{文章id}    //用户每点击一次,就执行一下这个命令,去给"article:readcount:{文章id}"这个key的值加1

  GET article:readcount:{文章id}    //通过GET命令,去获取"article:readcount:{文章id}"这个key的值

 

string的数据结构存在,就讲到这里,算是比较简单的操作。技术存储键值对就可以了。

 

(2)第二种是Hash数据结构: hash我们并不陌生,java中常用的hashmap是键值对的存在数据结构,我们不妨可以联系在一起,进行学习。

  我们先看看hash的常用操作:

  HSET key field value    //存储一个哈希表key的键值

  HSETNX key field value   //存在一个不存在的哈希表key的键值

  HMSET key field value [field value ...]  //在一个哈希表key中存储多个键值对

  HGET key field   //获取哈希表key对应的field键值

  HMGET key field [field ...]  //批量获取哈希表key中的field键值

  HDEL key field [field...]   //删除哈希表key 中的field的键值

  HLEN key        //返回哈希表key中field的数量

  HGETALL key    //返回哈希表key中所有的键值对

 

  HINCRBY key field increment   //为哈希表key中field键的值加上增量increment

好了,这些命令还是得记一记的,接下来我们举例子:

(1)如果有一个数据表:

 

 

 我们可以用hash数据结构来存在对象:

命令:HMSET user {userId}:name zhuge {userId}:balance 1888 [field value...]

具体操作:

  HMSET user 1:name zhuge 1:balance 1888  2:name yangguo 2:balance 16000

  HMGET user 1:name 1:balance  2:name 2:balance

 

操作完之后,我们就已经把id为1,和2的2个对象存入hash数据结构中了,大致结构如图:

 

 

 

 

 (2)电商购物车:我们对购物车并不陌生,那么购物车的功能我们也可以借助redis来实现,先看看一个购物车的图:

 

 

    (1)我们可以以用户ID为key

    (2)商品ID为field

    (3)商品数量为value

  购物车操作:

    1)添加商品:hset cart:1001 10088 1

    2)  增加数量:hincrby cart:1001 10088 1

    3)  商品总数:hlen cart:1001

    4)  删除商品:hdel cart:1001 10088

    5)  获取购物车所有商品:hgetall cart:1001

 

OK,到处位置,购物车的简单功能实现就是这些,主要就是对redis hash存在结构的简单操作。

那么hash结构的优缺点是什么呢:

  优点:

    1)同类数据归类整合存在,方便数据管理  (如上面的购物车例子,我们可以把每个人的购物车都归类起来,即每个key值每个人的购物车,key中的filed-value键值对所代表这个人购物车下的商品及数量)

    2)相比string操作消耗内存和cpu更小了  

    3)相比string存在更节省空间了

  缺点:

    1)过期功能不能使用在field上,只能使用在key上。 (存储格式,如下图,类似于一个hashMap<key,hashMap<field,aclue>>,双层hashmap结构)

 

 

    2)redis集群架构下不适合大规模使用。 (因为hash结构是一个整体,原则上不能分开存储,所以如果有多台机器,我们只能存储在其中一台机器上面,这样如果hash里面存储了很大的值,就会导致存储不平衡,大多数请求都打在一台机器上,所以不太适合)

 

(3)List结构:

  List常用操作:

    LPUSH key value [value...]    //将一个或者多个值value插入到key列表的表头(最左边,下图,LPUSH 指的是从列表的左边插入,L指的是left)

    RPUSH key value [value...]    // /将一个或者多个值value插入到key列表的表尾(最右边,下图,LPUSH 指的是从列表的右边插入,R指的是right)

    LPOP key            //移除并返回key的头元素

    RPOP key             //移除并返回key的尾元素

    LRANGE key start stop      //返回key列表中指定区间内的元素,区间以偏移量start和stop指定

    BLPOP key [key...] timeout    //从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,则一直阻塞等待。

    BRPOP key [key...] timeout    //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,则一直阻塞等待。

    (B表示 BLOCK ,L表示left,R表示right。这2个命令可以当做消息队列来用。即如果有消息就消费掉,如果没有消息就处于阻塞状态)

 

   常用的数据结构:

    Stack(栈,栈的特点先进后出FILO):LPUSH+LPOP。 即从队头进从队头出,就可以实现先进后出。

    Queue(队列,队列的特点先进先出FIFO):LPUSH+RPOP。 即从队头进,从队尾出,就可以实现先进先出。

    Blocking MQ(阻塞队列): LPUSH+BRPOP。即从队头进,从队尾阻塞出,就可以实现阻塞队列。

 

  举例子:我们对微博和微信公众号消息流并不陌生吧。我们每天都会随手刷一刷,如下图:

                                          

 

     以上2张图是微博和公众号的页面。相信我们经常会看见这个页面。我们可以利用我们学习的redis知识,来实现这些功能。

  就拿第二张图片来说,我关注了MacTalk和备胎说车2个大V。他们发推文的时候,我可以用一个List来存储他们的消息:

  1)MacTalk发推文,消息ID为10081;

    命令:LPUSH msg:{userId} 10081    //把10081这条消息插入到队列的头部

  2)备胎说车发推文,消息ID10082

    命令:LPUSH msg:{userId} 10082    //把10082这条消息插入到队列的头部

  3)查看最新消息:

    命令:LRANGE msg:{userId} 0 4     //从头部开始查询队列下标为0-4的元素

  简简单单的几个命令,就可以高性能的完成这个功能。当然微博和微信公众号里面的实现逻辑不仅仅是这么简单,还需要根据功能去分析,这里只是简单的代入。还需要各位小宝贝自行脑补思考。

 

(4)Set结构:

  常用的Set操作:

    SADD key member [member ...]    //往集合key中存入元素,元素存在则忽略,若集合key不存在则新建集合key

    SREM key member [member...]    //从集合key'中删除元素

    SMEMBERS key           //获取集合key中所有元素

    SCARD key             //获取集合key的元素个数

    SISMEMBER key member      //判断member元素是否在集合key中

    SRANDMEMBER key [count]    //从集合key中选出count个元素,元素不从集合key中删除

    SPOP key [count]          //从集合key中选出count个元素,元素从集合key中删除

  上面是Set(集合)结构的一些基操。接下来,是Set结构的一些运算操作:

    SINTER key [key...]             //交集运算

    SINTERSTORE destination key [key...]    //将交集的结构存入新集合destination中

    SUNION key [key...]            //并集运算

    SUNIONSTORE destination key [key...]    //将并集的结构存入新集合destination中

    SDIFF key [key..]              //差集运算

    SDIFFSTORE destination key [key...]      //将差集的结构存入新集合destination中

  OK,概念非常生硬,这里画几个图来解释一下:

  1)什么是集合运算:

    例如:有3个集合,集合set1,集合set2,集合set3                                                                  

       集合set1通过SADD set1  a b c,执行之后通过SMEMBERS set1 查询出来集合set1 ={a,b,c}

       集合set2通过SADD set2  b c d,执行之后通过SMEMBERS set2 查询出来集合set2 ={b,c,d}  

         集合set2通过SADD set3   c d e,执行之后通过SMEMBERS set3 查询出来集合set2 ={c,d,e}                  

                                    

 

 

 

 

 

 

       那么我们执行 SINTER set1 set2 set3 ,我们会获得set1,set2,set3,3个集合的交集我们可以发现3个集合都有“c”,所以我们获得 {c}    

 

 

 

      那么我们执行 SUNION set1 set2 set3 ,我们会获得set1,set2,set3,3个集合的并集,我们把集合的所有元素加起来并去除重复的,所以我们获得 {a,b,c,d,e}  

 

 

      

 

      那么我们执行 SDIFF set1 set2 set3 ,我们会获得set1,set2,set3,3个集合的差集(差集我们可以用第一个减去后面的来实现),所以我们获得 {a}    

 

 

  2)拿几个生活中的例子来说说Set集合的运用吧。看下图:

                               

上图是我们经常会在微信小程序上看见的抽奖活动,

1)当我们点击“参与抽奖”时:

   SADD key {userId}    //我们将我们的userId存入集合key中,有则不存

2)按钮“参与抽奖”下面有一排头像,我们可以查看参与抽奖的用户:

   SMEMBERS key    //查看key中所有的元素

3)开奖的时候,我们可以执行:

    SRANDMEMBER key [count]  //获取集合key中count名用户,用户不移除,接着下轮抽奖

  或者:

    SPOP key [count]    //获取集合key中count名用户,用户移除,下轮抽奖不参加了

      

 

 

 

  3)我们日常经常会刷微博吧,细心的小伙伴们肯定会发现,微博经常给我们推荐”共同关注“朋友,”我关注的人也关注了她“,如下图:

  

        

 

    ok,那这个功能是怎么实现的呢?

    例子:假如 刘一 关注了 王二,张三,李四   即 刘一   -》 {王二,张三,李四}

          王二 关注了 张三,孙五   即 王二   -》 {张三,孙五}

          张三 关注了 刘一,李四,孙五   即 张三   -》 {刘一,李四,孙五}

    1》 那么刘一 跟 张三 的共同关注好友,就可以利用命令:SINTER liuList zhangList ,获取到交集的结果是 =》{李四}

    2》 如果刘一 来到了 孙五 的微博,系统就会给刘一展示刘一关注的人中谁关注了孙五:

      我们就可以利用命令:

        SISMEMBER wangList sun     //查看刘一关注的王二中是否关注了孙五

        SISMEMBER zhangList sun     //查看刘一关注的张三中是否关注了孙五

        SISMEMBER liList sun       //查看刘一关注的李四中是否关注了孙五

    如果存在的话,说明他们也关注了孙五。  好了,可能名字比较多,小伙伴们细品,我相信可以品清楚的。

  

  4)我们日常中也经常刷淘宝吧,相信对下面这个图,肯定不陌生:

  

 

  

    当我们在选择条件的时候,最终系统会快速的帮我们筛选出来满足条件的商品,那它是怎么实现的呢?

    1》我们把每一个选项对应的商品都存在一个集合中,例如:

       SADD brand:huawei P40    //创建一个集合 brand:huawei 把元素 P40 存入

       SADD brand:xiaomi mi-10    //创建一个集合 brand:xiaomi 把元素 mi-10 存入

       SADD brand:iphone iphone12    //创建一个集合 brand:iphone 把元素 iphone12 存入

       SADD os:android P40 mi-10   //创建一个集合 os:android 把元素 P40 mi-10 存入

       SADD cpu:brand:inter P40 mi-10    //创建一个集合 cpu:brand:inter  把元素 P40 mi-10 存入

       SADD ram:8G  P40 mi-10 iphone12    //创建一个集合 ram:8G 把元素 P40 mi-10 iphone12 存入

 

     当我们选择选项为安卓系统,CPU是inter,内存是8G的时候,可以执行命令:

      SINTER os:android cpu:brand:inter ram:8G ==》 {P40 mi-10}     //我们求os:android cpu:brand:inter ram:8G 这3个集合的交集,为 {P40 mi-10}

 

  好了,到此为止Set结构就讲完了,举的例子比较多,小伙伴们可以细细品味。然后结合你在公司中具体的项目,看看是否也能运用redis来操作。

 

 

  (5)ZSet 有序集合结构:

    常用操作:

      ZADD key score member [[score member]...]      //往有序集合key中存放带分值(排序的值)的元素

      ZREM key member [member...]            //从有序集合key中删除元素

      ZSCORE key member                //返回有序集合key中元素member的分值

      ZINCRBY key increment member           //为有序集合key中元素member的分值加上increment

      ZCARD key                     //返回有序集合key中的元素个数

      ZRANGE key start stop [WITHSCORES]        //正序获取有序集合key从start下标到stop下标的元素

      ZREVRANGE key start stop [WITHSCORES]      //倒序获取有序集合key从start下标到stop下标的元素

    集合操作:

      ZUNIONSTORE destkey numkeys key [key...]      //并集计算

      ZINTERSTORE destkey numkeys key [key...]      //交集计算

  

  1)我们每天在刷微博热搜的时候,都是有顺序排列的,有榜一,榜二等等,如下图:

    

 

 

  那么我们用有序集合ZSet来实现排行榜:

    1》点击新闻:

      ZINCRBY hotNews:20210130 1 1001  //我们给集合 hotNews:20210130 中的新闻ID为1001的新闻加1

    2》展示当日排行前十:

      ZREVRANGE hotNews:20210130 0 9 WITHSCORES   //倒序的查询集合 hotNews:20210130 10条新闻

    3》七日搜索榜单计算:

      ZUNIONSTORE hotNews:20210130-20210205 7 hotNews:20210130 hotNews:20210131... hotNews:20210205

    4》展示七日排行前十:

      ZREVRANGE hotNews:20210130-20210205 0 9 WITHSCORES

 

总结:

   上面就是redis中,5大数据结构的操作。希望对初学者能够有帮助,如果对你有帮助的话,请留下的赞,如果有问题可以留言,我会尽量回复哦!!!

 

posted @ 2021-01-26 23:57  Takey  阅读(131)  评论(0编辑  收藏  举报