Redis系列(二)Redis的8种数据类型
本文内容纲要:
-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