史上最全Redis数据结构详解
记得点赞+在看呦。
前言在Redis最重要最基础就属它丰富的数据结构了,Redis之所以能脱颖而出很大原因是他数据结构丰富,可以支持多种场景。并且Redis的数据结构实现以及应用场景在面试中是相当常见的,接下来就和大家聊聊Redis的数据结构。
Redis数据结构有:string、list、hash、set、sortedset这五个是大家都知道的,如果在面试的时候能说出HyperLogLog、Geo、BloomFilter、bitMap这几个数据结构,那一定会让面试官眼前一亮的。
String基本概念:String是Redis最简单的数据结构,也是Memcached唯一的数据结构。在平时的开发中,String可以说是使用最频繁的了。底层实现:
如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面(将void*转换成long),并将字符串对象的编码设置为int。如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于39字节,那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值,并将对象的编码设置为raw。如果字符串对象保存的是一个字符串值,并且这个字符串值的长度小于等于39字节,那么字符串对象将使用embstr编码的方式来保存这个字符串值。更详细的Redis底层数据详解请看:超详细Redis五种数据结构底层实现使用:
redis_cli#启动redis-cli客户端sethelloworld#将键hello的值设置为worldOK#set命令成功后会返回OKgethello#通过get命令获取键为hello的值"world"#获得到的值delhello#删除键为hello的值(integer)1#返回的是删除的数量mseta10b20c30#批量的设置值OKmgetabc#批量的返回值1)"10"2)"20"3)"30"existshello#是否存在该键(integer)1#1表示存在,0表示不存在expirehello10#给hello设置过期时间,单位,秒(integer)1#返回1代表成功,0代表key不存在或无法设置过期时间pexpirehello10#给hello设置过期时间,单位,毫秒(integer)1#返回1代表成功,0代表key不存在或无法设置过期时间
接下来会重点讲一下setkeyvalue[EXseconds][PXmilliseconds][NX
XX]这个一系列命令,这块还是挺重要的,也很容易混淆。reids每次对以前的值覆盖时,会清空TLL值。(TTL是过期时间)
EXsecond:设置键的过期时间为second秒。SETkeyvalueEXsecond效果等同于SETEXkeysecondvalue。PXmillisecond:设置键的过期时间为millisecond毫秒。SETkeyvaluePXmillisecond效果等同于PSETEXkeymillisecondvalue。NX:只在键不存在时,才对键进行设置操作。SETkeyvalueNX效果等同于SETNXkeyvalue。XX:只在键已经存在时,才对键进行设置操作。#使用EX选项setkey1helloEX#设置过期时间sOKttlhello#获取hello的过期时间(integer)#使用PX选项setkey1helloPX#设置过期时间msOKttlhello#获取hello的过期时间(integer)#使用NX选项sethelloworldNXOK#键不存在,设置成功gethello"value"sethelloworldNX(nil)#键已经存在,设置失败gethello"world"#维持原值不变#使用XX选项existshello#先确定hello不存在(integer)0sethelloworldXX(nil)#因为键不存在,设置失败sethellowolrd#先给hello设置一个值OKsethellonewWolrdXXOK#这回设置成功了gethello"newWorld"#NX或XX可以和EX或者PX组合使用sethelloworldEXNXOKgethello"world"ttlhello(integer)sethellowolrdPXNXOKpttlhello(integer)#实际操作中这个值肯定小于,这次是为了效果才这么写的#EX和PX可以同时出现,但后面给出的选项会覆盖前面给出的选项sethellowolrdEXPXOKttlhello(integer)30#这个是PX设置的参数,pttlhello(integer)setnumber1OKincrnumber#对number做自增操作(integer)2
在开发过程中,用redis来实现锁是很常用的操作。结合NX以及EX来实现。
sethelloworldNXEX10#成功加锁,过期时间是10sOKsethellowolrdNXEX10#在10s内执行这个命令返回错误,以为上一次的锁还没有释放(nil)delhello#释放了锁OKsethelloworldNXEX10#成功加锁,过期时间是10sOKsetnxhelloworld#也可以这么写setexhello10wolrd
锁可以通过设置过期时间以及手动del删除来释放锁。string的命令比较常用就多介绍了点,下面的命令我就挑重点介绍了。应用场景:
缓存功能:string最常用的就是缓存功能,会将一些更新不频繁但是查询频繁的数据缓存起来,以此来减轻DB的压力。计数器:可以用来计数,通过incr操作,如统计网站的访问量、文章访问量等。List基本概念:list是有序可重复列表,和Java的List蛮像的,查询速度快,可以通过索引查询;插入删除速度慢。底层实现:
列表对象的编码可以是ziplist或者linkedlist。列表对象保存的所有字符串元素的长度都小于64字节并且保存的元素数量小于个,使用ziplist编码;否则使用linkedlist;更详细的Redis底层数据详解请看:超详细Redis五种数据结构底层实现使用:
lpushmylista#从左边插入数据(ineteger)1lpushmylistb(integer)1rpushmylistc#从右边插入数据(integer)1lrangemylist0-1#检索数据,lrange需要两个索引,左闭右闭;0就是从第0个,-1是倒数第一个,-2倒数第二个...以此类推1)"b"2)"a"3)"c"lrangemylist0-2#0到倒数第2个1)"b"2)"a"lpushmylistabc#批量插入(integer)3lpopmylist#从左侧弹出元素"b"rpopmylist#从右侧弹出元素"c"rpopmylist#当列表中没有元素时返回null(nil)brpoopmylist5#从右侧弹出元素,如果列表没有元素,会阻塞住,如果5s后还是没有元素则返回1)"mylist"#列表名2)"b"#弹出元素delmylist#删除列表(integer)1
使用场景:
消息队列:Redis的list是有序的列表结构,可以实现阻塞队列,使用左进右出的方式。Lpush用来生产从左侧插入数据,Brpop用来消费,用来从右侧阻塞的消费数据。数据的分页展示:lrange命令需要两个索引来获取数据,这个就可以用来实现分页,可以在代码中计算两个索引值,然后来redis中取数据。可以用来实现粉丝列表以及最新消息排行等功能。Hash简介:Redis散列可以存储多个键值对之间的映射。和字符串一样,散列存储的值既可以是字符串又可以是数值,并且用户同样可以对散列存储的数字值执行自增或自减操作。这个和Java的HashMap很像,每个HashMap有自己的名字,同时可以存储多个k/v对。底层实现:
哈希对象的编码可以是ziplist或者hashtable。哈希对象保存的所有键值对的键和值的字符串长度都小于64字节并且保存的键值对数量小于个,使用ziplist编码;否则使用hashtable;更详细的Redis底层数据详解请看:超详细Redis五种数据结构底层实现使用:
hsetstudentname张三#可以理解为忘名叫student的map中添加kv键值对(integer)1#返回1代表不存在这个key,并且添加成功hsetstudentsex男(integer)1hsetstudentname张三(integer)0#返回0因为这个key已经存在hgetallstudent1)"name"2)"张三"3)"sex"4)"男"hdelstudentname#删除这key(integer)1#返回1同样代表整个key存在并且删除成功hdelstudentname(integer)0#返回0是因为该key已经不存在
应用场景:
Hash更适合存储结构化的数据,比如Java中的对象;其实Java中的对象也可以用string进行存储,只需要将对象序列化成json串就可以,但是如果这个对象的某个属性更新比较频繁的话,那么每次就需要重新将整个对象序列化存储,这样消耗开销比较大。可如果用hash来存储对象的每个属性,那么每次只需要更新要更新的属性就可以。购物车场景:可以以用户的id为key,商品的id为存储的field,商品数量为键值对的value,这样就构成了购物车的三个要素。Set基本概念:Redis的set和list都可以存储多个字符串,他们呢之间的不同之处在于,list是有序可重复,而set是无序不可重复。底层实现:
集合对象的编码可以是intset或者hashtable。集合对象保存的所有元素都是整数值并且保存的元素数量不超过个,使用intset编码;否则使用hashtable;更详细的Redis底层数据详解请看:超详细Redis五种数据结构底层实现使用:
saddfamilymother#尝试将mother添加进family集合中(integer)1#返回1表示添加成功,0表示元素已经存在集合中saddfamilyfather(integer)1saddfamilyfather(intger)0smembersfamily#获取集合中所有的元素1)"mother"2)"father"sismemberfamilyfather#判断father是否在family集合中(integer)1#1存在;0不存在sismberfamilyson(integer)0sremfamilyson#移除family集合中元素son(integer)1#1表示存在并且移除成功;0表示存在该元素sremfamilysom(integer)0saddfamily1mother(integer)1smembersfamily1)"mother"2)"father"smemberfamily11)"mother"sinterfamilyfamily1#获取family和family1的交集1)"mother"saddfamily1son(integer)1sunionfamilyfamily1#获取family和family1的并集1)"mother"2)"father"sdifffamilyfamily1#获取family和family1的差集(就是family有但是family1没有的元素)1)"father"
应用场景:
标签:可以将博客网站每个人的标签用set集合存储,然后还按每个标签将用户进行归并。存储好友/粉丝:set具有去重功能;还可以利用set并集功能得到共同好友之类的功能。SortedSet基本概念:有序集合和散列一样,都用于存储键值对:其中有序集合的每个键称为成员(member),都是独一无二的,而有序集合的每个值称为分值(score),都必须是浮点数。可以根据分数进行排序,有序集合是Redis里面唯一既可以根据成员访问元素(这一点和散列一样),又可以根据分值以及分值的排列顺序来访问元素的结构。和Redis的其他结构一样,用户可以对有序集合执行添加、移除和获取等操作。底层实现:
有序集合的编码可以是ziplist或者skiplist有序集合保存的元素数量小于个并且保存的所有元素成员的长度都小于64字节。使用ziplist编码;否则使用skiplist;更详细的Redis底层数据详解请看:超详细Redis五种数据结构底层实现使用:
zaddclassmember1#将member1元素及其score值加入到有序集合class中(integer)1zaddclass90membermember3#批量添加(integer)2zrangeclass0-1withscores#获取有序集合中的值与score,并按score排序1)"member3"2)"80"3)"member2"4)"90"5)"member1"6)""zremclassmember1#删除class中的member1(integer)1
应用场景:
排行榜:有序集合最常用的场景。如新闻网站对热点新闻排序,比如根据点击量、点赞量等。带权重的消息队列:重要的消息score大一些,普通消息score小一些,可以实现优先级高的任务先执行。蘑菇睡不着
转载请注明:http://www.sonphie.com/jibzd/14328.html