首页 文章资讯内容详情

Redis系列(二)Redis的8种数据类型

2026-06-01 3 花语

本文内容纲要:

-1、Redis的五大数据类型 -Redis-key -1、String(字符串) -2、List(列表) -3、Set(集合) -4、Hash(哈希) -5、zset(有序集合) -2、Redis三种特殊数据类型 -1、geospatial -2、hyperloglog -3、bitmap位图

NoSQL开发中或多或少都会用到,也是面试必问知识点。最近这几天的面试每一场都问到了。但是感觉回答的并不好,还有很多需要梳理的知识点。这里通过几篇Redis笔记整个梳理一遍,后面再加上面试题。

Redis系列:

Redis系列(一)Redis入门 Redis系列(二)Redis的8种数据类型 Redis系列(三)Redis的事务和SpringBoot整合 Redis系列(四)Redis配置文件和持久化 Redis系列(五)发布订阅模式、主从复制和哨兵模式 Redis系列(六)Redis的缓存穿透、缓存击穿和缓存雪崩 Redis系列(七)Redis面试题 Redis命令参考

1、Redis的五大数据类型

官网可查看命令:http://www.redis.cn/commands.html

Redis-key

127.0.0.1:6379>keys* (emptylistorset) 127.0.0.1:6379>setnamexxx OK 127.0.0.1:6379>keys* 1)"name" 127.0.0.1:6379>setage1 OK 127.0.0.1:6379>keys* 1)"age" 2)"name" 127.0.0.1:6379>existsname #判断key是否存在 (integer)1 127.0.0.1:6379>existsname1 (integer)0 127.0.0.1:6379>movename1 (integer)1 127.0.0.1:6379>keys* 1)"age" 127.0.0.1:6379>setnameyyy OK 127.0.0.1:6379>expirename10#设置key的过期时间,单位是秒 (integer)1 127.0.0.1:6379>ttlname #查看当前key的剩余过期时间 (integer)7 127.0.0.1:6379>ttlname (integer)-2 127.0.0.1:6379>typeage #查看当前key的类型 string 127.0.0.1:6379>

Redis有以下5种基本的数据类型

1、String(字符串)

127.0.0.1:6379>setkey1v1 #设置值 OK 127.0.0.1:6379>getkey1 "v1" 127.0.0.1:6379>appendkey1"hello" #追加值,如果不存在,相当于setkey (integer)7 127.0.0.1:6379>getkey1 "v1hello" 127.0.0.1:6379>strlenkey1 #获取字符串长度 (integer)7 127.0.0.1:6379>

自增、自减

127.0.0.1:6379>setviews0 OK 127.0.0.1:6379>getviews "0" 127.0.0.1:6379>incrviews #自增1 (integer)1 127.0.0.1:6379>getviews "1" 127.0.0.1:6379>decrviews#自减1 (integer)0 127.0.0.1:6379>decrviews (integer)-1 127.0.0.1:6379>getviews "-1" 127.0.0.1:6379>incrbyviews10 #设置步长、自增10 (integer)9 127.0.0.1:6379>decrbyviews5#设置步长、自减5 (integer)4

字符串范围

127.0.0.1:6379>setkey1"hello,world!" OK 127.0.0.1:6379>getkey1 "hello,world!" 127.0.0.1:6379>getrangekey103 #截取字符串[0,3] "hell" 127.0.0.1:6379>getrangekey10-1 #获取全部的字符串,和getkey一样 "hello,world!" 127.0.0.1:6379>

替换:

127.0.0.1:6379>setkey2abcdefg OK 127.0.0.1:6379>getkey2 "abcdefg" 127.0.0.1:6379>setrangekey21xx (integer)7 127.0.0.1:6379>getkey2 "axxdefg" 127.0.0.1:6379>

setex(setwithexpire):设置过期时间

和setnx(setifnotexist):不存在再设置(在分布式锁中会经常使用)

127.0.0.1:6379>setexkey330"hello" #设置30秒后过期 OK 127.0.0.1:6379>ttlkey3 #剩余过期时间 (integer)25 127.0.0.1:6379>setnxmykey"redis" #mykey不存在时设置成功 (integer)1 127.0.0.1:6379>keys* 1)"key2" 2)"key1" 3)"views" 4)"mykey" 127.0.0.1:6379>setnxmykey"mongoDB" #mykey存在时设置失败 (integer)0 127.0.0.1:6379>getmykey #mykey值不变 "redis" 127.0.0.1:6379>

mset和mget

127.0.0.1:6379>msetk1v1k2v2k3v3 #同时设置多个值 OK 127.0.0.1:6379>keys* 1)"k1" 2)"k3" 3)"k2" 127.0.0.1:6379>mgetk1k2k3 #同时获取多个值 1)"v1" 2)"v2" 3)"v3" 127.0.0.1:6379>msetnxk1v1k4v4#msetnx是一个原子性的操作,要么一起成功,要么都失败 (integer)0 127.0.0.1:6379>getk4 (nil) 127.0.0.1:6379>

对象

setuser:1{name:zhangsan,age:3}#设置一个user:1对象值为json字符来保存一个对象 127.0.0.1:6379>msetuser:1:namezhangsanuser:1:age2 OK 127.0.0.1:6379>mgetuser:1:nameuser:1:age 1)"zhangsan" 2)"2" 127.0.0.1:6379>

getset:先get再set

127.0.0.1:6379>getsetdbredis #如果不存在值,则返回nil (nil) 127.0.0.1:6379>getdb "redis" 127.0.0.1:6379>getsetdbmongodb #如果存在值,获取原来的值,并设置新的值 "redis" 127.0.0.1:6379>getdb "mongodb" 127.0.0.1:6379>

String的使用场景:value除了是字符串以外还可以是数字

计数器 统计多单位的数量 粉丝数 对象缓存存储

2、List(列表)

基本的数据类型,列表。

在Redis中可以把list用作栈、队列、阻塞队列。

list命令多数以l开头。

127.0.0.1:6379>lpushlistone #将一个值或者多个值,插入到列表的头部(左) (integer)1 127.0.0.1:6379>lpushlisttwo (integer)2 127.0.0.1:6379>lpushlistthree (integer)3 127.0.0.1:6379>lrangelist0-1 #查看全部元素 1)"three" 2)"two" 3)"one" 127.0.0.1:6379>lrangelist01 #通过区间获取值 1)"three" 2)"two" 127.0.0.1:6379>rpushlistright #将一个值或者多个值,插入到列表的尾部(右) (integer)4 127.0.0.1:6379>lrangelist0-1 1)"three" 2)"two" 3)"one" 4)"right" 127.0.0.1:6379>

弹出pop

127.0.0.1:6379>lrangelist0-1 1)"!" 2)"world" 3)"world" 4)"hello" 127.0.0.1:6379>lpoplist #移除list的第一个元素 "!" 127.0.0.1:6379>lrangelist0-1 1)"world" 2)"world" 3)"hello" 127.0.0.1:6379>rpoplist #移除list的第一个元素 "hello" 127.0.0.1:6379>lrangelist0-1 1)"world" 2)"world" 127.0.0.1:6379>

索引Lindex

127.0.0.1:6379>lrangelist0-1 1)"hjk" 2)"world" 3)"world" 127.0.0.1:6379>lindexlist1 #通过下标获取list中的某一个值 "world" 127.0.0.1:6379>lindexlist0 "hjk" 127.0.0.1:6379>

Llen长度:

127.0.0.1:6379>llenlist (integer)3 127.0.0.1:6379>

移除指定的值:

127.0.0.1:6379>lrangelist0-1 1)"hjk" 2)"world" 3)"world" 127.0.0.1:6379>lremlist1world #移除list集合中指定个数的value,精确匹配 (integer)1 127.0.0.1:6379>lrangelist0-1 1)"hjk" 2)"world" 127.0.0.1:6379>lpushlisthjk (integer)3 127.0.0.1:6379>lrangelist0-1 1)"hjk" 2)"hjk" 3)"world" 127.0.0.1:6379>lremlist2hjk (integer)2 127.0.0.1:6379>lrangelist0-1 1)"world" 127.0.0.1:6379>

trim截断

127.0.0.1:6379>lrangemylist0-1 1)"hello1" 2)"hello2" 3)"hello3" 4)"hello4" 127.0.0.1:6379>ltrimmylist12#通过下标截取指定长度,这个list已经被破坏了,截断之后只剩下截断后的元素 OK 127.0.0.1:6379>lrangemylist0-1 1)"hello2" 2)"hello3" 127.0.0.1:6379>

rpoplpush:移除列表的最后一个元素,将他移动到新的列表中。

127.0.0.1:6379>lrangemylist0-1 1)"hello1" 2)"hello2" 3)"hello3" 127.0.0.1:6379>rpoplpushmylistmyotherlist #移除列表的最后一个元素,将他移动到新的列表中。 "hello3" 127.0.0.1:6379>lrangemylist0-1 #查看原来的列表 1)"hello1" 2)"hello2" 127.0.0.1:6379>lrangemyotherlist0-1 #查看目标列表中,确实存在该值 1)"hello3" 127.0.0.1:6379>

lset:将列表中指定下标的值替换为另一个值,更新操作

127.0.0.1:6379>existslist #判断这个列表是否存在 (integer)0 127.0.0.1:6379>lsetlist0item #如果不存在的话,更新会报错 (error)ERRnosuchkey 127.0.0.1:6379>lpushlistvalue1 (integer)1 127.0.0.1:6379>lrangelist00 1)"value1" 127.0.0.1:6379>lsetlist0item #如果存在,更新当前下标的值 OK 127.0.0.1:6379>lsetlist1other #如果不存在的话,更新会报错 (error)ERRindexoutofrange 127.0.0.1:6379>

linsert:将某个具体的value插入到列表中某个元素的前面或者后面

127.0.0.1:6379>lrangemylist0-1 1)"hello1" 2)"hello2" 127.0.0.1:6379>linsertmylistbefore"hello2"hello (integer)3 127.0.0.1:6379>lrangemylist0-1 1)"hello1" 2)"hello" 3)"hello2" 127.0.0.1:6379>linsertmylistafter"hello2"hello (integer)4 127.0.0.1:6379>lrangemylist0-1 1)"hello1" 2)"hello" 3)"hello2" 4)"hello" 127.0.0.1:6379>

小结

list实际上是一个链表,前后都可以插入 如果key不存在,创建新的链表 如果移除了所有的值,空链表,也代表不存在 在两边插入或者改动值,效率最高。

3、Set(集合)

127.0.0.1:6379>saddmyset"hello" #set集合中添加元素 (integer)1 127.0.0.1:6379>saddmyset"world" (integer)1 127.0.0.1:6379>smembersmyset #查看指定Set的所有值 1)"world" 2)"hello" 127.0.0.1:6379>sismembermysethello #判断某一个值是不是在set中 (integer)1 127.0.0.1:6379>sismembermysethello1 (integer)0 127.0.0.1:6379> 127.0.0.1:6379>scardmyset #获取集合中的个数 (integer)2 127.0.0.1:6379>saddmyset"hello2" (integer)1 127.0.0.1:6379>smembersmyset 1)"world" 2)"hello2" 3)"hello" 127.0.0.1:6379>sremmysethello#移除元素 (integer)1 127.0.0.1:6379>smembersmyset 1)"world" 2)"hello2" 127.0.0.1:6379> 127.0.0.1:6379>smembersmyset 1)"kkk" 2)"world" 3)"hjk" 4)"hello2" 127.0.0.1:6379>srandmembermyset #随机抽取一个元素 "hjk" 127.0.0.1:6379>srandmembermyset "hello2" 127.0.0.1:6379>srandmembermyset2 #随机抽取指定个数的元素 1)"world" 2)"hello2" 127.0.0.1:6379>srandmembermyset2 1)"hello2" 2)"hjk" 127.0.0.1:6379> 127.0.0.1:6379>smembersmyset 1)"kkk" 2)"world" 3)"hjk" 4)"hello2" 127.0.0.1:6379>spopmyset #随机删除元素 "hjk" 127.0.0.1:6379>smembersmyset 1)"kkk" 2)"world" 3)"hello2" 127.0.0.1:6379>spopmyset "hello2" 127.0.0.1:6379>smembersmyset 1)"kkk" 2)"world" 127.0.0.1:6379> 127.0.0.1:6379>smembersmyset 1)"kkk" 2)"world" 127.0.0.1:6379>saddmyset2set2 (integer)1 127.0.0.1:6379>smovemysetmyset2"kkk" #将一个特定的值,移动到另一个set集合中 (integer)1 127.0.0.1:6379>smembersmyset 1)"world" 127.0.0.1:6379>smembersmyset2 1)"kkk" 2)"set2" 127.0.0.1:6379> 127.0.0.1:6379>smemberskey1 1)"b" 2)"a" 3)"c" 127.0.0.1:6379>smemberskey2 1)"e" 2)"d" 3)"c" 127.0.0.1:6379>sdiffkey1key2 #差集 1)"b" 2)"a" 127.0.0.1:6379>sinterkey1key2#交集 1)"c" 127.0.0.1:6379>sunionkey1key2 #并集 1)"e" 2)"a" 3)"c" 4)"d" 5)"b"

4、Hash(哈希)

也是key-value形式的,但是value是一个map。

127.0.0.1:6379>hsetmyhashfieldxxx #set一个key-value (integer)1 127.0.0.1:6379>hgetmyhashfield #获取一个字段值 "xxx" 127.0.0.1:6379>hmsetmyhashfield1hellofield2world #set多个key-value OK 127.0.0.1:6379>hmgetmyhashfieldfield1field2 #获取多个字段值 1)"xxx" 2)"hello" 3)"world" 127.0.0.1:6379>hgetallmyhash #获取全部的数据 1)"field" 2)"xxx" 3)"field1" 4)"hello" 5)"field2" 6)"world" 127.0.0.1:6379>hdelmyhashfield1 #删除指定的key,对应的value也就没有了 (integer)1 127.0.0.1:6379>hgetallmyhash 1)"field" 2)"xxx" 3)"field2" 4)"world" 127.0.0.1:6379> 127.0.0.1:6379>hlenmyhash #获取长度 (integer)2 127.0.0.1:6379>hexistsmyhashfield1#判断指定key是否存在 (integer)0 127.0.0.1:6379>hexistsmyhashfield2 (integer)1 127.0.0.1:6379>hkeysmyhash #获取所有的key 1)"field" 2)"field2" 127.0.0.1:6379>hvalsmyhash #获取所有的value 1)"xxx" 2)"world" 127.0.0.1:6379> 127.0.0.1:6379>hsetmyhashfield35 (integer)1 127.0.0.1:6379>hincrbymyhashfield31 #指定增量 (integer)6 127.0.0.1:6379>hincrbymyhashfield3-1 (integer)5 127.0.0.1:6379>hsetnxmyhashfield4hello #如果不存在则可以设置 (integer)1 127.0.0.1:6379>hsetnxmyhashfield4world #如果存在则不能设置 (integer)0 127.0.0.1:6379>

Hash适合存储经常变动的对象信息,String更适合于存储字符串。

5、zset(有序集合)

127.0.0.1:6379>zaddmyset1one #添加一个值 (integer)1 127.0.0.1:6379>zaddmyset2two3three #添加多个值 (integer)2 127.0.0.1:6379>zrangemyset0-1 1)"one" 2)"two" 3)"three" 127.0.0.1:6379>

实现排序:

127.0.0.1:6379>zaddsalary2500xiaohong (integer)1 127.0.0.1:6379>zaddsalary5000xiaoming (integer)1 127.0.0.1:6379>zaddsalary500xaiozhang (integer)1 127.0.0.1:6379>zrangesalary0-1 1)"xaiozhang" 2)"xiaohong" 3)"xiaoming" 127.0.0.1:6379>zrangebyscoresalary-inf+inf #从小到大显示全部的用户 1)"xaiozhang" 2)"xiaohong" 3)"xiaoming" 127.0.0.1:6379>zrevrangesalary0-1 #从大到小进行排序 1)"xiaoming" 2)"xiaohong" 3)"xaiozhang" 127.0.0.1:6379>zrangebyscoresalary-inf+infwithscores#附带成绩的显示所有用户 1)"xaiozhang" 2)"500" 3)"xiaohong" 4)"2500" 5)"xiaoming" 6)"5000" 127.0.0.1:6379>zrangebyscoresalary-inf2500withscores #显示工资小于2500的用户 1)"xaiozhang" 2)"500" 3)"xiaohong" 4)"2500" 127.0.0.1:6379>zrangesalary0-1 1)"xaiozhang" 2)"xiaohong" 3)"xiaoming" 127.0.0.1:6379>zremsalaryxiaohong#移除特定元素 (integer)1 127.0.0.1:6379>zrangesalary0-1 1)"xaiozhang" 2)"xiaoming" 127.0.0.1:6379>zcardsalary #获取有序集合的个数 (integer)2 127.0.0.1:6379> 127.0.0.1:6379>zaddmyset1hello (integer)1 127.0.0.1:6379>zaddmyset2world3! (integer)2 127.0.0.1:6379>zcountmyset13 #获取指定区间的人员数量 (integer)3 127.0.0.1:6379>zcountmyset12 (integer)2

2、Redis三种特殊数据类型

1、geospatial

Redis在3.2推出Geo类型,该功能可以推算出地理位置信息,两地之间的距离。

文档:https://www.redis.net.cn/order/3687.html

借助网站模拟一些数据:http://www.jsons.cn/lngcode/

geoadd添加地理位置

规则:两极无法直接添加,一般会下载城市数据,直接通过Java程序一次性导入。

有效的经度从-180度到180度。有效的纬度从-85.05112878度到85.05112878度。当坐标位置超出指定范围时,该命令将会返回一个错误。

(error)ERRinvalidlongitudelatitudepairxxxyyy

添加一些模拟数据:

127.0.0.1:6379>geoaddchina:city116.4039.90beijing (integer)1 127.0.0.1:6379>geoaddchina:city121.4731.23shanghai (integer)1 127.0.0.1:6379>geoaddchina:city106.5029.53chongqing114.0522.52shengzhen (integer)2 127.0.0.1:6379>geoaddchina:city120.1630.24hangzhou108.9634.26xian (integer)2 127.0.0.1:6379>

geopos获得当前定位坐标值

127.0.0.1:6379>geoposchina:citybeijing #获得指定城市的经纬度 1)1)"116.39999896287918091" 2)"39.90000009167092543" 127.0.0.1:6379>geoposchina:cityshanghai 1)1)"121.47000163793563843" 2)"31.22999903975783553" 127.0.0.1:6379>

geodist获取两个位置之间的距离

单位:

m表示单位为米。 km表示单位为千米。 mi表示单位为英里。 ft表示单位为英尺。

如果用户没有显式地指定单位参数,那么GEODIST默认使用米作为单位。

127.0.0.1:6379>geodistchina:citybeijingshanghaikm #查看北京和上海直接的直线距离 "1067.3788" 127.0.0.1:6379>geodistchina:citybeijingchongqingkm "1464.0708" 127.0.0.1:6379>

georedius以给定的经纬度为中心,找出某一半径内的元素

127.0.0.1:6379>georadiuschina:city110301000km#以110,30这个点为中心,寻找方圆1000km的城市 1)"chongqing" 2)"xian" 3)"shengzhen" 4)"hangzhou" 127.0.0.1:6379>georadiuschina:city11030500km 1)"chongqing" 2)"xian" 127.0.0.1:6379>georadiuschina:city11030500kmwithcoord #显示他人的定位信息 1)1)"chongqing" 2)1)"106.49999767541885376" 2)"29.52999957900659211" 2)1)"xian" 2)1)"108.96000176668167114" 2)"34.25999964418929977" 127.0.0.1:6379> 127.0.0.1:6379>georadiuschina:city11030500kmwithdist#显示到中心点的距离 1)1)"chongqing" 2)"341.9374" 2)1)"xian" 2)"483.8340" 127.0.0.1:6379>georadiuschina:city11030500kmwithdistwithcoordcount1#指定数量 1)1)"chongqing" 2)"341.9374" 3)1)"106.49999767541885376" 2)"29.52999957900659211" 127.0.0.1:6379>georadiuschina:city11030500kmwithdistwithcoordcount2 1)1)"chongqing" 2)"341.9374" 3)1)"106.49999767541885376" 2)"29.52999957900659211" 2)1)"xian" 2)"483.8340" 3)1)"108.96000176668167114" 2)"34.25999964418929977" 127.0.0.1:6379>

GEORADIUSBYMEMBER找出位于指定元素周围的其他元素

127.0.0.1:6379>georadiusbymemberchina:cityshanghai1000km 1)"hangzhou" 2)"shanghai" 127.0.0.1:6379>

geo底层实现原理其实就是zset,可以使用zset命令操作geo

127.0.0.1:6379>zrangechina:city0-1 1)"chongqing" 2)"xian" 3)"shengzhen" 4)"hangzhou" 5)"shanghai" 6)"beijing" 127.0.0.1:6379>zremchina:citybeijing #删除一个元素 (integer)1 127.0.0.1:6379>zrangechina:city0-1 1)"chongqing" 2)"xian" 3)"shengzhen" 4)"hangzhou" 5)"shanghai" 127.0.0.1:6379>

2、hyperloglog

基数:数学上集合的元素个数,是不能重复的。

UV(Uniquevisitor):是指通过互联网访问、浏览这个网页的自然人。访问的一个电脑客户端为一个访客,一天内同一个访客仅被计算一次。

Redis2.8.9版本更新了hyperloglog数据结构,是基于基数统计的算法。

hyperloglog的优点是占用内存小,并且是固定的。存储2^64个不同元素的基数,只需要12KB的空间。但是也可能有0.81%的错误率。

这个数据结构常用于统计网站的UV。传统的方式是使用set保存用户的ID,然后统计set中元素的数量作为判断标准。但是这种方式保存了大量的用户ID,ID一般比较长,占空间,还很麻烦。我们的目的是计数,不是保存数据,所以这样做有弊端。但是如果使用hyperloglog就比较合适了。

127.0.0.1:6379>pfaddmykeyabcdefghij #创建第一组元素 (integer)1 127.0.0.1:6379>PFCOUNTmykey #统计mykey基数 (integer)10 127.0.0.1:6379>PFADDmykey2ijzxcvbnm#创建第二组元素 (integer)1 127.0.0.1:6379>PFCOUNTmykey2 #统计mykey2基数 (integer)9 127.0.0.1:6379>PFMERGEmykey3mykeymykey2 #合并两组mykeymykey2=>mykey3 OK 127.0.0.1:6379>PFCOUNTmykey3 (integer)15 127.0.0.1:6379>

3、bitmap位图

bitmap就是通过最小的单位bit来进行0或者1的设置,表示某个元素对应的值或者状态。一个bit的值,或者是0,或者是1;也就是说一个bit能存储的最多信息是2。

bitmap常用于统计用户信息比如活跃粉丝和不活跃粉丝、登录和未登录、是否打卡等。

这里使用一周打卡的案例说明其用法:

127.0.0.1:6379>setbitsign01 #周一打卡了 (integer)0 127.0.0.1:6379>setbitsign10 #周二未打卡 (integer)0 127.0.0.1:6379>setbitsign20 #周三未打卡 (integer)0 127.0.0.1:6379>setbitsign31 (integer)0 127.0.0.1:6379>setbitsign41 (integer)0 127.0.0.1:6379>setbitsign51 (integer)0 127.0.0.1:6379>setbitsign60 (integer)0 127.0.0.1:6379>

查看某一天是否打卡:

127.0.0.1:6379>GETBITsign3 (integer)1 127.0.0.1:6379>GETBITsign6 (integer)0 127.0.0.1:6379>

统计:统计打卡的天数

127.0.0.1:6379>BITCOUNTsign (integer)4 127.0.0.1:6379>

下一篇笔记将介绍Redis的事务和SpringBoot整合Redis。

本文内容总结:1、Redis的五大数据类型,Redis-key,1、String(字符串),2、List(列表),3、Set(集合),4、Hash(哈希),5、zset(有序集合),2、Redis三种特殊数据类型,1、geospatial,2、hyperloglog,3、bitmap位图,

原文链接:https://www.cnblogs.com/itzhouq/p/redis22.html