瑞吉外卖--Redies
一:Redis简介:
Redis 是一个基于"内存"的key-value结构的"数据库"。(内存数据库)
Redis是NoSql数据库,即"非关系型数据库";
传统的关系型数据库MySql,主要存储在磁盘上; 而Redis主要主要在内存;
Redis优点:
1.基于"内存"存储、读写性能高。
2.适合存储"热点数据" (即在短时间内会有大量用户访问的数据 eg:热点商品、咨询、新闻、计数器,排行榜)
3.企业应用广泛;
Redis应用场景:
1.缓存(使用比较多)
2.任务队列
3.消息队列
4.分布式锁
## 二:Redis数据类型
~~~java
(1)"这里的数据类型指的是value的数据类型,key的类型都为字符串"!!!
value有10大数据类型
(2)String是Redis的基本数据类型,一个key对应一个value!!!
(3)String类型是二进制最安全的,意思是redis的String可以包含任何数据,比如jpg图片或者序列化的对象
1.Redis常用10种数据类型:
介绍:Redis存储的是key-value结构的数据,其中key是"字符串类型",
"value" 有"5种常用的数据类型":!!!!
1.字符串: String 类型,常用
2.哈希:hash :适合存储"对象"
3.列表:list :按照插入顺序排序,可以有重复元素
4.无序集合:set :无序集合,没有重复元素
5.有序集合:sorted set :有序集合,没有重复元素
三:Redis常用命令
Redis常用命令:用来操作Redis中的数据; (类似于通过sql语句操作mySql数据库)
(1).字符串String
1.字符串String操作命令
(1)
1. set key value :设置指定key的值; "如果key相同的话,后面的value会覆盖之前的key"
eg: set name xiaoming
2. GET key :获取指定key的值
3.keys *:查看所有的key
4.exists key :检查给定key是否存在
5.type key:查看key所存储的value的数据类型
6.del key :删除指定的key数据
7.ttl key: 查看指定key还有多少s过期(-1表示永不过期,-2表示已过期)
8. expire key +s :为指定的key设置过期时间
9.select dvindex :切换数据库【0-15】,默认为0 --> :eg: select 0
10. move key dbindex【0-15】:将当前数据库的key迁移到指定的数据库dbindex中 -->eg: move k1 3
11:dbsize:查看当前数据库key的数理
12:flushdb :清空当前库("慎用")
13:flushall:通杀所有数据库("慎用")
(2)
//同时设置/获取多个键值
1.mset key1 value1...:同时设置多个键值k-v -->:eg: set k1 v1 k2 v2...
2.mget key1...:同时获取多个value -->:eg: mget k1 k2 ...
//获取/设置指定区间范围内的值
1.getrange key:返回指定区间的值(0表示第一位,-1表示最后一位) -->eg: getrange k1 0 -1
2.setrange key:设置指定区间的值("可覆盖原来的") -->eg:setrange k1 0 aa:使用"aa""覆盖"k1对应的value的第一位起
//数值增减("一定要是数字才能进行增减")
1.incr key:为key对应value增加1
2.incrby key +数字 :为key对应value增加指定数字
3.decr key:为key对应value减少1
2.decrby key +数字 :为key对应value减少指定数字
//获取字符串长度/字符串内容追加
strlen key :获取key对应value长度
append key +内容:value内容追加
//分布式锁
1.setex key seconds value : 设置指定key的值,并将key的过期时间设为seconds秒; ("常用于手机验证码")
eg: setex city 10 beijing
2.setnx key value :只有key不存在时设置key的值,如果key存在就不执行;
//将key的值设置为value,并返回key的旧值(old value)
getset key value
2.string应用场景
(3)string类型value的运用场合:
--抖音点赞/收藏(incr key)
(2).哈希hash操作命令:
1.哈希简介:
KV模式不变,但是V是一个键值对
2.哈希hash操作命令
Redis hash 是一个String类型的field 和value的映射表, hash特别适合用于存储 "对象"
"哈希结构":
value
field1 value1
key ----->
field2 value2
//插入数据 /获取数据
1. hset key field value : 将哈希表的key中的字段 的field值设置为value ("可以为key追加多个field-value")
eg: hset user:001(对象):name xiaoming :"将user:001对象的name属性/字段设置为xiaoming"
hset user:001 age 20 address sjz : "将user:001对象的age属性/字段设置为20,address=sjz"
2. hget key field : 获取存储在哈希表中指定字段(field)的值(value)
eg: hget 001 name : "获取001对象的name属性/字段的值"
hget 001 age : "获取001对象age属性字段的值"
//获取某个key内的全部field数量: heln
hlen key -->:heln user:001
//key内是否存在某个字段: hexists
hexists key field ---> hexists user:001 name
//删除
hdel key field : 删除存储在哈希表中的指定字段
eg: hdel 001 age : "删除001对象的age属性/字段的值"
//获取哈希表key中的所有field和value :hkeys / hvals
1. hkeys key : 获取哈希表key中所有字段(即所有的field)
eg: hkeys 001 : "获取001对象的所有属性/字段field"
2. hvals key : 获取哈希表key中所有的值 (即所有的value)
eg: hvals 001 : "获取001对象的所有的value"
3. hgetall key : 获取在哈希表中指定key的所有字段和值 (即返回所有的field 和 value)
eg: hegetall 001 : "返回001对象所有的field 和 value"
//为哈希表中的key对应的value(整数/小数)增加对应的值: hincrby / hincrbyfloat
1.hincrby key field + 数字 -->:hincrby user1:001 source 1
2.hincrbyfloat key field + 数字:--> hincrbyfloat user:001 source 0.5
//不存在则赋值,存在则操作无效 :hsetnx
hsetnx key filed-value
(3).列表list:
1.list介绍
list:是一个"双端链表"的结构,主要功能有"push/pop"等,一般用在栈、队列、消息队列等场景;
"单key多value"
left、right都可以插入添加
如果键不存在,创建新的链表
如果已存在,新增内容
如果值全移除,对应键也就消失了
list:
(1)Redis 列表 是 "简单的字符串列表"(列表中的每一个元素都是"字符串类型"的) ,按照"插入顺序排序";
(2)列表中的元素可重复、有序、为字符串(!!!!)
(3)"使用list可以做 任务队列!!!!"
(4) "列表结构":
value
key -----> | a | b | c | d |
"尾部" "头部"
下标: 0 1 2 3
遍历顺序: ------------->("从尾部到头部")
2.列表list操作命令:
//插入 /查询(lpush、rpush、lrnage)
1.lpush key value [value2] :将一个或多个值插入到"列表头部"
eg: lpush mylist a b c : "向 列表mylist 头部 依次插入 a b c"
2.lrange key start stop :获取列表指定范围内的元素 ("遍历的适合是从尾部开始,到头部!!!!!!!!!")
eg: lrange mylist 0 -1 : '代表获取 列表mylist 从第一个到最后一个的元素'
"查询结果为" :"c" (因为 a先插入,b其次,c最后插入) ---> mylist : | c | b | a |
"b"
"a"
3.rpush key value...:将一个或多个值插入到"列表尾部"
eg: rpush mylist a b c : "向 列表mylist 尾部 依次插入 a b c"
之后:lrange key start stop
eg: lrange mylist 0 -1 :
"查询结果为" :"a" ---> mylist : | a | b | c |
"b"
"c"
//移除列表中最后一个加入的元素: (lpop、rpop)
1.lpop key
2..rpop key :移除并获取列表中的"最后一个元素"
eg: rpop mylist :"移除并返回 mylisy列表 的最后一个元素 即 :c"
//list按下标取得值(lindex)
1. lindex key +下标
//获取list列表中元素个数(llen)
1.llen key : 获取列表list长度(元素的个数)
//lrem key 数字N 给定值v1 :从left往右删除N个等于v1的元素
eg: lrem key 0 :表示删除key列表全部给定的值。 "0个就是全部值" ==del 列表
//ltrim key 开始index 结束index: 截取指定范围的值然后再赋值给key
//rpoplpush:移除列表的最后一个元素,并将该元素加到另一个列表,并返回 rpoplpush list1 list2
//lset key index value:使用value替换list中下标为index的值
//linsert key before/after value1 value2:在value1前面/后面 插入value2
5. brpop key1 [key2] timeout : 移除并返回最后一个元素("即队尾(最右边)")的值, 如果列表没有元素就会阻塞列表指导等待超时 或 发现可弹出元素为止;
eg:
当列表有元素时: brpop mylist 10 : " 移除并返回最后一个元素的值"
当列表没有元素时: brpop mylist 10 : "会一直阻塞,直到10s结束"
(3)list应用场景:
eg:关注了订阅了一些作品,只要更新作品之后,他的作品就会依次进入我的list,然后按顺序排好
4.集合set操作命令:
(1)set介绍:
Set: 单值多value、无重复
(2)无序集合 Redis set
Redis set 是 "String类型"的"无序"集合,集合成员是"无重复"的,这就意味着集合中不能出现重复的数据
----------------------------------------基础操作-----------------------------
//添加元素 / 遍历集合
1.sadd key member1 [member2] :向集合中添加一个或多个成员
eg:sadd myset a b c d :"向 集合myset 中插入 a b c d"
sadd myset2 a b x y::"向 集合myset 中插入 a b x y"
2.semembers key : 返回集合中的所有成员
eg:semebers myset: "返回 集合myset 中的所有成员(无序)"
3.sismember 集合 元素 :判断元素是否在集合中
sismember myset 1
4..scard key :获取集合的成员数
eg: scard myset
5.srem key member1 [member2]:移除集合中一个或多个成员 //删除集合中的元素
eg: srem myset a b c : "移除 集合myset中的 a b c"
-------------------------------------------------------------------------------------------------------
srandmember key 数字:从集合中随机展现 数字个数个元素,元素"不删除" --> srandmember myset 2:从myset中随机展现两个元素!!
spop key 数字:从集合中随机弹出一个元素,出一个在集合中"删除"1个 --> spop member 2:从集合member中随机弹出两个元素(之后这两个元素就不会再出现在member集合中)
------------------------------------------剪切操作-----------------------------------
smove key1 key2:将key1里面已经存在的某个值 "拿出然后赋给"key2 --->smove member member1 4:将集合member集合中的4拿出然后赋值(放入)到member1集合中
------------------------------------------集合运算("!!!!!!!!!!!!!!!!!!!!!")---------------------------------
1.sinter key1 [key2] :返回给定所有集合的交集
eg: sinter myset myset2 : "返回 集合myset 和 集合myset2 的交集" --> "即 "a" "b"
sintercard numberkeys(即几个key) key1 key2 limit +数字 :返回 将集合key1 和key2 去重+交集的个数
limit:代表让它返回几个
2.sunion key1 [key2] : 返回给定所有集合的并集
eg: siunion myset myset2 : "返回集合myset 和集合myset2 的并集"
3.sdiff key1 [key2] : 返回给定所有集合的差集("注意两个集合的前后顺序")
eg: sdiff myset myset2 : "myset 和 myset2的差集 :即 myset-myset2 :--> "c" "d"
eg: sdiff myset2 myset : "myset2 和 myset的差集 : 即myset2-myset : --> "x" "y"
(3)set应用场景:
主要应用:集合运算
1.微信抽奖小程序:
a:有多少人想要参加: sadd key 用户id ("用户点击立即参与按钮--后台执行")
b:显示有多少人参加了: scard key("统计key里面有多少")
c:抽奖(从set中任意选取N个中奖人):--srandmember key 2("随机抽奖两个人,元素不删除)
b:spop key [数字] --有人抽到一个序号就去掉一个;--spop key 3: "随机抽奖3个人,元素删除
2.微信朋友圈点赞
a: 新增点赞:sadd pub:myID(key) 点赞用户ID1 点赞用户ID2
b:取消点赞: srem pub:myID 点赞用户ID
c:展现所有点赞过的数据:smembers pub:msID
d:点赞人数:scard key
e:判断某个朋友是否对我点赞: sismember pub:myID 用户ID
3.可能认识的人:
b: "差集" sdiff key1 key2
5有序集合 Redis sorted set
(1)Zset介绍:
在set基础上,每个value值前面加了一个"score"分数值,作为排序的参考值
eg: 之前--> key v1 v2...
| |
"Zset"--> key score v1 score2 v2...
(2)zset命令
Redis sorted set "有序集合"是"String类型元素"的集合,且"不允许重复"的成员。
每一个元素都会关联一个"double类型"的分数(score)。
Redis正是"通过分数"来"为集合中的成员进行从小到大排序"。
有序集合的"成员是唯一"的,但是"分数可以重复";
1. zadd key score1 member1 [score2 member2] :向 有序集合 添加一个或多个成员, 或者更新已经存在的成员的分数
eg: zadd myset3 10.0 a 9.0 b : "向 有序集合myset3 中 添加 a(10.0) b(9.0)"
-------------------------------------"取值"------------------------------------------------
2.(1)zrange key start stop [withscores] : 通过索引区间 返回有序集合中指定区间内的成员
eg: zrange myset3 0 -1 : "查看 有序集合myset3 内的成员(按照分数从小到大排序!!!)---> 即 b a"
zrange myset3 0 -1 withscores :"返回元素的同时也返回对应的分数"
(2)zrevrange .......:反转:"从大到小排列"
(3)zrangebyscore key minscore maxscore withscores :查找zset中分数在 [minscore,maxscore]之间的元素
(4)zrangebyscore key (a b withscores :查找zset中分数在 (a,b]中的元素
(5).................limit -->:limit:作用是返回限制
(6)zscore key value :获取zset中对应value的分数
-------------------------------------"增加"
3.zincrby key increment member :有序集合中对指定成员/元素的分数加上增量 increment
eg: zincrby myset3 20 b : "给 有序集合myset3 中的 b元素的分数 +20"
4. zrem key member [member...] :移除有序集合中的一个或多个成员
eg: zrem myset3 b : "移除 集合myset3 的 b元素"
5.zcard key:返回zset中的value数量
6.zcount key score1 score2:返回在score1-score2之间的元素个数
7.("???")zmpop keynumber(几个key:eg:1/2/3) key min count 1 :
---zmpop 1 zset min count 1:从zset中弹出
--------------------------------"返回下标"-----------
zrank key value:返回下标
zrevrank ... :逆序返回下标
(3)Zset应用场景:
热销的商品榜单
打赏排行榜
eg: 思路:
a:定义商品的排行榜: 使用"Zset" ,key为goods:sellsort, score为商品销售数量
b:eg: 商品编号1001卖了10个,1002卖了11个 : zsadd goods:sellsort 10 1001 11 1002
c:有客户又去买了2件商品1001,则商品1001销量+2 :zincrby goods:sellsort 2 1001
d:求销量前10名: zrange goods:sellsort 0 9 withsocres
6.位图(bitmap):
(1)位图介绍
1.位图(bitmap):由0和1状态表现的二进制位的"bit数组" (0表示No,1表示Yes)
2.需求:
用于状态统计---Y/N
3.位图本质是:"String类型的数组" (也可以用String的部分命令:get...)
(2)基本命令:
1.setbit
setbit key offset("偏移量从0开始") value(只能设置为0/1)
eg: serbit k1 1 1:将bitmap的第一位设置为1 :--eg:"可以表示某个人在第一天进行了打卡"
serbit k1 2 0:将bitmap的第一位设置为0 :--eg:"可以表示某个人在第一天每有进行了打卡"
setbit bit1 0 1
setbit sign:u1:2024910(key) 3 1
2.getbit key offset:获取bitmap对应位的值
3.strlen key:
注:"8位是一个字节(即下标0-7为一个字节)"
4. bitcount: 统计key对应的位图1的数量
eg: bitcount uid:1ogin123
也可以统计比如某段连续时间内都签到的人数:
eg: setbit 2024910 0 1
setbit 2024910 1 0
setbit 2024911 0 1
setbit 2024911 1 1
5. bitop and key 2024910 2024911 :返回这连续两天都登录的人数
7.HyperLogLog
(1)HyperLogLog介绍:
1.需求:
a:统计某个网站的UV、统计某个文章的UV -->什么是UV:独立访客,一般理解为客户端IP ("需要去重处理")
b:用户搜素网站关键词的数量
c:统计用户每天搜索不同词条的个数
2.HyperLogLog就是-->"去重复统计功能的基数估计算法"
基数:是一种数据集,去重复之后的真实个数
"基数统计"
eg: (全集)I={2,4,6,8,77,9,4,8,10} --"去掉重复的内容"--> 基数={2,4,6,8,77,39,10}="7"
eg: 每天这么多人访问网站,但是8号访问了多次,所以统计今天一共多少人访问:--去重复之后 一共7人
3.HyperLogLog是"String类型"
"注意":它"不会"存储存入的元素本身所以并不会像集合那样返回具体的记录/元素,只是会返回"去重后的基数统计值";
(2)基本命令:
1. pfadd key eleHment [element...]:添加指定元素(element)到HyperLogLog中("一般是ip地址")
-->: pfadd hyperlog1 1 3 4 7 9 5
2. pfcount key [key...] :返回给定HyperLogLog的基数估算值("去重之后的基数值")
3. pfmerge destkey sourcekey [sourcekey...]: 将多个HyperLogLog合并为一个HyperLogLog
-->: pfmerge hyperlog3 hyperlog1 hyperlog2 -->hyperlog3即为合并之后的HyperLogLog
8.地理空间GEO
(1)GEO简介:
1.GEO简介:地理位置处理
原理:
将三维的地球变为二维的坐标
再将二维的坐标转换为一维的点块
最后将一维的点块转换转换为二进制再通过base32编码
2.需求:
eg:移动互联网时代的:交友软件的app、外卖软件附近的店铺、滴滴打车的位置信息;
(2)命令:
1.geoadd key 经度 纬度 位置名称 [经度 纬度 位置名称...]: "存储指定的地理空间位置"
eg: geoadd city 116.403963 39.915119 "天安门"
"注意":GEO是Zset类型 "经度、维度就相当于分数!!!!!!!!!!!!!!!!!"
2.geopos key "地址":返回GEO里面地址的经纬度
eg: geops city "天安门"
3.!!!geohash key "地址...":"用geohash(哈希编码)表示坐标(经纬度)" :geohash算法生成的base32编码值、3维变2维变1维:
eg: geohash city 天安门 故宫
"将经纬度做了映射" -->eg: 116.403963 39.915119 --wx4g0f6f2v0
4.geodist key "地址1" "地址2" 单位(eg:m/km...) :两个地址直接的距离
eg:geodist city 天安门 长城 m
5.!!!georadius: 以"给定的经纬度为中心",查找附近的xxx
参数:
1:withdist: 在返回位置的同时,将位置元素与中心元素之间的"距离也一并返回"。距离的单位和用户给定的范围单位保持一致;
2.withcoord:将位置的经纬度也一并返回
3.withhash:以52位有符号整数形式返回位置元素
4.count +数字:限定返回的记录数
eg: georadius city 116.6665 39.4523 10 km withdish withcoord withhash count 10
--->查找以 "经纬度:116.6665 39.4523" 为中心 返回它 10km内的位置的元素+经纬度+52位hash编码形式+返回10条数据
6.georandiusbymember: 以"给定的位置元素为中心",查找指定范围内的元素
eg: georandiusbymember city 天安门 10 km withdish withcoord withhash count 10
9.Redis流(Stream)
(1).Redis流(Strem流)简介:
1. Redis - Strem :"就是Redis版的MQ:消息中间键 + 阻塞队列"
stream的类型是"stream"
2.Redis消息队列的两种方案:(了解即可)
(1)List实现消息队列(下图) :list实现方式其实就是点对点的模式--即"一进一出" "一对一"
(2)pub/sub
3.Redis - Strem能干嘛:
实现消息队列,它支持消息的持久化,支持自动生成全局唯一ID、支持ack确认消息的模式、支持消费组模式等,让消息队列更加稳定可靠
"注意":Stream不能100%等价于Kafka、RabbitMQ来使用,生产案例少,慎用
4.底层结构: Redis - Strem是一个消息链表,会将所有加入的消息串起来,每个消息都有一个唯一的ID和对应的内容
(2)基本命令
1.基本命令理论简介:
1.队列相关指令 :"消息和消息内容的生产者,一生产就放到队列里面"
2.消费组相关指令:将多个消费者放到一个消费组里面,消费组用来读取这些消息
3.特殊符号:("类似于MySql中的between、and")
2.基本命令
a:. 队列相关命令/更多的是生产者相关命令:
1. 队列相关命令/生产者相关命令: -->"即如何向Stream中添加消息"
(1):xadd:向Stream队列中添加消息,如果指定的Stream流不存在,则该命令执行时会新构建一个Stream队列(添加消息到队列末尾) ("先 进先出")
a: 消息ID必须比上一个ID大
b: 默认用星号表示自动生成消息ID ,后面顺序跟着 一堆 业务key/value: " * 用于xadd命令,让系统自动生成id"
eg: xadd mystream * id 11 name zs -->:"1726057454100-0"(这个就是生成的消息ID:格式:时间戳-自增ID)
xadd mystream * k1 v1 k2 v2 k3 v3
(2)xrange: 用于获取消息列表(可以指定范围),忽略删除的消息
start:表示开始值, -代表最小值
end:表示结束值, +代表最大值
count:表示最多获取多少个值
eg: xrange mystream - + :表示返回mystream 中的所有消息
1) "1726057454100-0" ------> key
2) 1) "id"
2) "11"
3) "name" ------------>value:这些都是value:value是什么格式的都行!!!!
4) "zs"
xrange mystream - + count 1: 表示返回mystream 中的1条消息 ("先进先出!!!")
(3)xrevrange: 反转输出stream中的消息
eg: xrevrange mystream + -
(4)xdel stream id(主键eg:1726057454100-0):删除指定id的消息
(5)xlen:用于获取Stream流队列的长度
(6)xtrim:用于对Stream的长度进行截取,如超长会进行截取
maxlen:"允许最大长度",对流进行剪切限制长度
minid:"允许最小id",从某个id值开始 比该id小的都会被抛弃
eg1: xtrim mystream "maxlen" 2: 允许最大长度是2即--在stream中剩下2条信息,其余的都截去("且被截取的是时间戳小的--先进先 出")
eg2: xtrim mystream "minid" 1726057473646-0: 允许最小id是1726057473646-0,比这个id小的都会被从stream中去掉;
(7)xread:"用于获取消息"(阻塞/非阻塞),只会返回大于指定ID的消息
count:最多读取多少条消息
block:是否以阻塞的方式读取消息,默认为不阻塞,如果milliseconds设置为0,表示永远阻塞;
--->xread [count num:返回几条数据] [block milliseconds] streams key [key...] ID [ID...]
1.:读取"非阻塞"消息:
eg: xread count 10 streams mystream 0-0 :表示从mystream中读取10条数据(0-0:表示"从最小ID开始获取stream中的消息,从头 读到尾部,当不指定count时,将会返回stream中的所有消息",也可以使用0(00/000...))
2.:获取"阻塞"消息:(类似于java中的阻塞队列)
eg: xread count 1 block 0 stream mystream $:表示阻塞队列
之后外我们新开一个客户端:执行xadd mystream * k8 v8之后,之前的阻塞队列的客户端会立即弹出新的ID即k8 v8的ID!!!
"$:代表特殊ID,表示监听来获取最大的ID,如果已经是最大ID了的话,就返回nil;"
b.消费组相关指令
消费者/组:消费队列中的消息,需要将消费者分组创建消费组
1.---->用于创建消费组: xgroup create 队列名称 分组名称 0/$
"注意": (1)"$":表示从Stream尾部开始消费
(2)"0":表示从Stream头部开始消费
"创建消费者组的时候必须指定ID,ID为0表示从头开始消费,ID为$表示只消费新的消息---即队尾新来的消息"
eg: xgroup create mystream groupX $ (从尾部开始读)
xgroup create mystream groupA 0 (从头读到尾)
2.------>用于消费组读取stream队列中的消息: xreadgroup group :
一:一个消费者全读:
(1)">":表示从第一条尚未被消费的消息开始读取 (即:游标,读取一条消息后,游标就会往前走)
(2)"!!!!!!!!"
A:stream中的消息一旦被消费组的1个消费者读取之后,这个消费组的其它消费掌者就不能再读取了
--->即同一个消费组的消费者不能消费同一条消息
B:但是 "不同消费组"的消费者可以消费同一条消息
--------------------------->"即按组进行读取消息"
以xgroup create mystream groupA 0为例
1.eg : xreadgroup group groupA consumer1 stream mystream >
"表示:groupA消费组中的consume1消费者读取mystrem队列中的消息,然后就会返回mystream中的消息,之后再用这个消费组的其它消费者读取这个队列中的消息eg: xreadgroup group groupA consumer2 stream mystream > 就会返回空值nil,因为consume1消费者以已经将游标从头刷到尾了"
2.eg: xreadgroup group groupB consumer1 stream mystream >
"groupB组的消费者仍然可以读取,但是也只能1个消费者进行读取"
二: 让组内的每一个消费者都读取一部分消息,实现负载均衡
eg:
xreadgroup group groupC consumer1 count 1 streams mystream >
xreadgroup group groupC consumer2 count 2 streams mystream >
"令groupC消费组的consumer1读取mystrems的1条消息,consumer2读取2条消息"
3."!!!!"已读已签收(ack) 和 已读未签收
(1)xpedning stream流名称 消费组---> xpending:查询每个消费组内的所有消费者 ["已读取、但尚未确定" 的消息]
eg1:
xpending mystream groupC:
1) (integer) 2 --->代表mystream流中共有两条消息
2) "1726057454100-0" -->代表:所有消费者读取的最小消息的ID
3) "1726138115816-0" -->代表: 所有消费者读取的最大消息的ID
4) 1) 1) "consumer1" -->代表:consumer1读取了1条数据
2) "1"
2) 1) "consumer2" -->代表:consumer1读取了1条数据
2) "1"
eg2:xpending mystream groupC - + 10 consumer2 :返回10条groupC消费组的consumer2读取mystream但未确认的消息
(2)Xack:向消息队列发送确认消息
eg1: xack mystream groupC "1726057454100-0" :表示向消息队列发送确认信息,确认"1726057454100-0"对应的消息"已读取 已确认"; --->之后xpending 就不会出现这条消息了
4. xinfo:用于打印stream/消费者/分组 的详细信息
-->xinfo stream mystream
10:位域:bitfield(了解即可)
11.通用命令:
通用命令: "针对key" 进行操作,即针对不同的类型都可以使用这些命令
1.keys pattern :查找所有符合给定模式的(pattern) 的"key"
eg: keys * ("!!!!") : "查找所有的key"
"001"
"name"
"myset3"
"age"
"myset"
"key1"
"myset2"
2.exists key :检查给定key是否存在
eg: exists name "检查name是否存在"
3.type key :返回key所存储的值value的类型
eg: type name --> "String"
4. tll key :返回给定key的剩余生存时间(TLL,time to live),以秒为单位
5. del key :该命令 用于在key存在时删除key-value
四:在Java中操作Redis(!!!)
1.使用"Jedis"操作Redis
1.使用"Jedis"操作Redis中的数据
2."注意": 方法名和命令是一样的 !!!!!!!!!
3.案例:
public void testRedis(){
//1.获取连接,连接到Redis
Jedis jedis=new Jedis("localhost",6379); //指定连接的Redis服务(localhost本地)
//2.执行具体操作
"(1)下面以String类型数据进行操作!!!"
//eg:我们要操作一个字符串类型的数据 比如向Redis中存入一个string类型的值 --key-value
jedis.set("username","xiaoming");
//get查询
String value= jedis.get("username");
System.out.println(value);
//del删除
jedis.del("username");
"(2)下面以哈希类型数据进行操作!!!"
//操作哈希类型的数据: eg:向Redis中存入(hset)一个哈希类的值 key-value
jedis.hset("myhash","addr","beijing");
//获取哈希的值:hget , 指定key,指定value
String hValue = jedis.hget("myhash", "addr");
System.out.println("hValue="+hValue);
"(3)java中Redis的通用命令!!!"
Set<String> keys = jedis.keys("*"); (=keys *)
//3.关闭连接
jedis.close();
}
2.使用Spring Data Redis 操作Redis(!!!!!!!!!!)
1."在Spring Boot项目中,使用Spring Data Redis来简化Redis操作!!!!!!!!!"
//操作Redis:通过redisTemplate模板类 调用相应的方法可以获取相应的对象,然后通过相应的对象来操作相应的数据!!!
Spring Data Redis 底层是对jedis作的封装
2.导入maven坐标:spring-boot-starter-data-redis
Spring Data Redis
Spring Data Redis 提供了一个高度封装的类:" RedisTemplate ",针对jedis客户端中大量的api进行来归类封装,将同一类型操作封装为operation接口,具体分类如下:
ValueOperations:简单K-V操作 (eg:String类型的数据)
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作(eg:有序集合类型的数据)
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据进行操作
注意:"5个接口,来操作5种对应的数据类型"
(1)Spring Data Redis 操作String数据
public class SpringDataRedisTest {
@Autowired
private RedisTemplate redisTemplate; //只要application.yml中写了配置,就可以注入进来
//操作Redis:通过redisTemplate模板类 调用相应的方法可以获取相应的对象,然后通过相应的对象来操作相应的数据!!!
/**
* (1)操作String类型数据,即简单的K-V
* -->通过redisTemplate调用opsForValue()方法获得ValueOperations对象,然后使用这个对象来通过set等方法对String数据进行操作
*/
@Test
public void testString(){
/*ValueOperations valueOperations = redisTemplate.opsForValue(); //获取对象
valueOperations.set("city","beijing"); */
//a:通过set方法为String类型数据赋值
redisTemplate.opsForValue().set("city123","beijing"); //连着写
//b:通过get方法获取
String value=(String) redisTemplate.opsForValue().get("city123");
System.out.println("Value="+value);
//c:设置过期时间
redisTemplate.opsForValue().set("key0","value0",10l, TimeUnit.SECONDS); //key-value 10 单位:秒
//d:只有key不存在时设置key的值,如果key存在就不执行 (set key value)
Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("city123", "nanjing");
System.out.println("aBoolean="+aBoolean); //false:代表"city123"已经存在,不会执行这条语句
}
}
(2)Spring Data Redis 操作Hash数据
/**
* (2)操作Hash类型数据
* -->通过redisTemplate调用opsForHash()方法获得HashOperations对象,然后使用这个对象来通过put等方法对Hash数据进行操作
*/
@Test
public void testHash(){
//获取hashOperations对象
HashOperations hashOperations = redisTemplate.opsForHash();
//a:存值:使用Hash"存储"对象的数据 (eg:为对象002存储数据)
hashOperations.put("002","name","ikun");
hashOperations.put("002","aeg","20");
hashOperations.put("002","addr","beijing");
//b:取值
String age = (String)hashOperations.get("002", "age");
System.out.println("age="+age);
//c:获取hash结构中所有的字段(field)
Set keys = hashOperations.keys("002");
for (Object key : keys) {
System.out.println(key);
}
//d:获取hash结构中所有的值value
List values = hashOperations.values("002");
for (Object value : values) {
System.out.println(value);
}
(3)Spring Data Redis 操作List列表数据
/**
* (3)操作List类型数据
* -->通过redisTemplate调用opsForList()方法获得listOperations对象,然后使用这个对象来通过leftPush等方法对List数据进行操作
*/
@Test
public void testList(){
//获得listOperations对象
ListOperations listOperations = redisTemplate.opsForList();
//a:存数据(leftPus):根据插入的顺序进行排序,且可以有重复元素
listOperations.leftPush("mylist1","a"); //存一个
listOperations.leftPushAll("mylist1","b","c","d");//存多个
//b:取值:range()
List<String> mylist = listOperations.range("mylist1", 0, -1);
for (String value : mylist) {
System.out.println(value);
}
//c:获取列表长度:size()
Long size = listOperations.size("mylist1");
System.out.println("size="+size);
//d:rightPop() key :移除并获取列表中的"最后一个元素"
Object o = listOperations.rightPop("mylist1");
System.out.println(o);
}
(4)Spring Data Redis 操作Set无序集合数据
/**
* (4)操作Set类型数据:无序且不可重复
* -->通过redisTemplate调用opsForSet()方法获得setOperations对象,然后使用这个对象来通过add()等方法对Set数据进行操作
*/
@Test
public void testSet(){
//获取setOperations对象
SetOperations setOperations = redisTemplate.opsForSet();
//a:存值:add()
setOperations.add("myset","a","b","c","a");
//b:取值:members()
Set<String>myset = setOperations.members("myset");
for (String o : myset) {
System.out.println(o);
}
//c:删除成员:remove()
setOperations.remove("myset","a","b");
System.out.println("111");
//取值:members()
myset = setOperations.members("myset");
for (String o : myset) {
System.out.println(o);
}
(5)Spring Data Redis 操作ZSet有序集合数据
/**
* (5)操作ZSet有序集合:有序(是根据分数从小到大进行排序)且不可重复
* -->通过redisTemplate调用opsForZSet()方法获得zSetOperations对象,然后使用这个对象来通过add()等方法对ZSet数据进行操作
*/
@Test
public void testZSet(){
//获取zSetOperations对象
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
//a:存值:add() key-value-source(double类型)
zSetOperations.add("myZset","a",10.0);
zSetOperations.add("myZset","b",11.0);
zSetOperations.add("myZset","c",12.0);
zSetOperations.add("myZset","a",13.0); //会覆盖原来a的值,所以a=13
//b:取值:range()
Set<String> myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println("s="+s);
}
------------------->: b、c、a
//c:修改分数:incrementScore():为myZset成员的b元素,增加20分
zSetOperations.incrementScore("myZset","b",20.0);
//取值:range()
myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println("修改完分数之后的排序s1="+s);
}
------------------->: c、a、b
//d:删除成员:remove()
zSetOperations.remove("myZset","a","b");
//取值:range()
myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println("删除a,b元素之后的排序s2="+s);
}
------------------->: c
}
(6)通用操作:针对不同的数据类型都可以操作
/**
* (6)通用操作
*
*/
@Test
public void testCommon(){
//a:获取Redis中所有的key -->keys("*")
Set keys = redisTemplate.keys("*");
for (Object key : keys) {
System.out.println("key="+key);
}
//b:判断某个key是否存在 -->hasKey("key名称")
Boolean b = redisTemplate.hasKey("itcast");
System.out.println(b);
//c:删除指定key -->delete("key名称")
redisTemplate.delete("myZset");
//d:获取指定key对应的value的数据类型 --type("key名称")
DataType dataType = redisTemplate.type("mySet");
System.out.println("Myset的数据类型是:"+dataType);
}