2.Redis7核心数据结构
Redis7 核心数据结构 知识体系总览Redis7 数据结构全景✅ Redis7 有哪些数据结构✅ 永远的神help 命令一、核心数据结构✅1. String 字符串字符串常用操作原子加减操作Key 的层级结构String 常见应用场景✅2. Hash 哈希Hash 常用操作String vs Hash 存储对象对比Hash 应用场景Hash 结构优缺点✅3. List 列表List 常用操作List 应用场景List 注意事项✅4. Set 集合Set 常用操作Set 运算操作Set 应用场景✅5. ZSet 有序集合ZSet 常用操作ZSet 集合运算ZSet 应用场景排行榜二、扩展数据结构✅6. Bitmap 位图Bitmap 常用操作Bitmap 应用场景每日签到✅7. HyperLogLogHyperLogLog 常用操作使用示例✅8. Geo 地理位置Geo 常用操作Geo 应用场景附近商家推荐三、高级数据结构✅9. Stream 消息流Stream 常用操作Stream 消费者组操作四、SpringBoot 集成 Redis✅10. Maven 依赖与配置✅11. RestTemplate 快速上手✅12. RedisTemplate 解决中文乱码 全文总结✅1. 数据结构总览对比✅2. 面试高频考点✅3. 数据结构选择决策树 知识体系总览Redis7 核心数据结构 ├── 数据结构全景 │ ├── ✅ 核心版 vs 扩展版 │ └── ✅ help 命令 ├── 一、核心数据结构 │ ├── ✅1. String 字符串 │ ├── ✅2. Hash 哈希 │ ├── ✅3. List 列表 │ ├── ✅4. Set 集合 │ └── ✅5. ZSet 有序集合 ├── 二、扩展数据结构 │ ├── ✅6. Bitmap 位图 │ ├── ✅7. HyperLogLog │ └── ✅8. Geo 地理位置 ├── 三、高级数据结构 │ └── ✅9. Stream 消息流 └── 四、SpringBoot 集成 Redis ├── ✅10. Maven 依赖与配置 ├── ✅11. RestTemplate 快速上手 └── ✅12. RedisTemplate 中文乱码解决Redis7 数据结构全景✅ Redis7 有哪些数据结构Redis7 的数据结构分为核心版和扩展版两大类别✅ 永远的神help 命令在 Redis 中help命令是学习数据结构的最佳入口通过help group可以查看任意数据结构的完整命令列表。 面试要点面试官常问Redis有哪些数据结构标准回答是5 种核心数据结构String、Hash、List、Set、ZSet 4 种扩展数据结构Bitmap、HyperLogLog、Geo、Stream。Bitmap 本质是 String 的位操作Geo 基于 ZSet 实现。一、核心数据结构✅1. String 字符串 关键理解String 是 Redis 中最基础的数据类型其 value 根据字符串格式不同分为 3 类string普通字符串、int整数类型、float浮点类型其中 int 和 float 可以做自增自减操作。底层是动态字符串SDS。最大容量 512MB。字符串常用操作命令说明SET key value存入字符串键值对key 不存在则新增存在则修改GET key获取一个字符串键值MSET key value [key value ...]批量存储字符串键值对MGET key [key ...]批量获取字符串键值SETNX key value存入一个不存在的字符串键值对SETEX key seconds value存入字符串键值对并指定有效期秒DEL key [key ...]删除一个键EXPIRE key seconds设置一个键的过期时间秒APPEND key value向字符串末尾追加内容使用示例127.0.0.1:6379setname Rose# key 不存在则新增OK127.0.0.1:6379get nameRose127.0.0.1:6379setname Jack# key 已存在则修改OK127.0.0.1:6379get nameJack127.0.0.1:6379MSET k1 v1 k2 v2 k3 v3 OK127.0.0.1:6379MGET name k1 k2 k31)Jack2)v13)v24)v3原子加减操作命令说明INCR key将 key 中储存的数字值加 1DECR key将 key 中储存的数字值减 1INCRBY key increment将 key 所储存的值加上 increment负数则减DECRBY key decrement将 key 所储存的值减去 decrement使用示例127.0.0.1:6379setage10OK127.0.0.1:6379incr age# 自增1(integer)11127.0.0.1:6379incrby age2# 自增2(integer)13127.0.0.1:6379incrby age-1# 加负数 减(integer)12127.0.0.1:6379decr age# 自减1(integer)11Key 的层级结构Redis 没有类似 MySQL 的 Table 概念如何区分不同类型的 key 呢可以通过给 key 添加前缀用:分隔多个单词形成层级结构多级 key 格式项目名:业务名:类型:id例如user 相关test:user:1product 相关test:product:1如果 Value 是一个 Java 对象可以将对象序列化为 JSON 字符串后存储test:user:1 → {id:1, name: Jack, age: 21} test:product:1 → {id:1, name: 小米11, price: 4999}在可视化界面中Redis 会以层级结构来展示更加直观方便管理。String 常见应用场景① 单值缓存SET key value GET key② 对象缓存-- 方式一JSON 字符串简单但不能单独操作字段 SET user:1{name:roy,balance:1888}-- 方式二多键存储推荐便于单独操作每个属性 MSET user:1:name roy user:1:balance1888MGET user:1:name user:1:balance③ 分布式锁SETNX product:10001true# 返回1获取锁成功返回0失败-- 执行业务操作 DEL product:10001# 执行完业务释放锁-- 推荐写法原子操作加锁 设置过期时间防止死锁 SET product:10001trueEX10NX✅2. Hash 哈希 关键理解Hash 类型也叫散列其 value 是一个无序字典类似于 Java 中的HashMap结构。适合存储对象将一个对象的多个属性存储在一个 key 下可以针对单个 field 做 CRUD。底层使用 listpack小数据量或 hashtable大数据量。Hash 常用操作命令说明HSET key field value存储一个哈希表 key 的键值field 不存在则新增存在则修改HGET key field获取哈希表 key 对应的 field 键值HSETNX key field value存储一个不存在的哈希表 key 的键值HMSET key field value [field value ...]在一个哈希表 key 中存储多个键值对HMGET key field [field ...]批量获取哈希表 key 中多个 field 键值HGETALL key返回哈希表 key 中所有的 field 和 valueHKEYS key获取一个 hash 类型的 key 中的所有 fieldHVALS key获取一个 hash 类型的 key 中的所有 valueHDEL key field [field ...]删除哈希表 key 中的 field 键值HLEN key返回哈希表 key 中 field 的数量HINCRBY key field increment为哈希表 key 中 field 键的值加上增量 increment使用示例127.0.0.1:6379HSET heima:user:3 name Lucy# field 不存在则新增(integer)1127.0.0.1:6379HSET heima:user:3 age21(integer)1127.0.0.1:6379HSET heima:user:3 age17# field 存在则修改(integer)0127.0.0.1:6379HGET heima:user:3 nameLucy127.0.0.1:6379HGET heima:user:3 age17127.0.0.1:6379HMSET heima:user:4 name LiLei age20sexmanOK127.0.0.1:6379HMGET heima:user:4 name age sex1)LiLei2)203)man127.0.0.1:6379HGETALL heima:user:41)name2)LiLei3)age4)205)sex6)man127.0.0.1:6379HKEYS heima:user:41)name2)age3)sex127.0.0.1:6379HINCRBY heima:user:4 age2# age 自增2(integer)22String vs Hash 存储对象对比方式写法优点缺点StringJSONSET user:1 {name:Jack,age:21}简单直接修改单个字段需反序列化整个 JSONString多键MSET user:1:name Jack user:1:age 21可单独操作每个属性key 数量多管理不便HashHSET user:1 name Jack age 21归类整合、节省空间、可单独操作 fieldfield 不支持独立设置过期时间Hash 应用场景① 对象缓存HSET user:1 name roy balance1888HMGET user:1 name balance② 电商购物车以用户 id为 key商品 id为 field商品数量为 value-- 添加商品 HSET cart:1001100881-- 增加数量 HINCRBY cart:1001100881-- 商品总数 HLEN cart:1001 -- 删除商品 HDEL cart:100110088-- 获取购物车所有商品 HGETALL cart:1001Hash 结构优缺点优点缺点同类数据归类整合储存方便数据管理过期功能不能使用在 field 上只能用在 key 上相比 string 操作消耗内存与 CPU 更小Redis 集群架构下不适合大规模使用相比 string 储存更节省空间—✅3. List 列表 关键理解List 与 Java 中的LinkedList类似底层是一个双向链表。支持正向和反向检索。特征有序、元素可重复、插入删除快、查询速度一般。一个 list 的容量是 2^32-1 个元素约 40 多亿。使用时要注意大 key 问题。List 常用操作命令说明LPUSH key value [value ...]将一个或多个值插入到 key 列表的表头最左边RPUSH key value [value ...]将一个或多个值插入到 key 列表的表尾最右边LPOP key移除并返回 key 列表的头元素列表为空则返回 nilRPOP key移除并返回 key 列表的尾元素列表为空则返回 nilLRANGE key start stop返回列表 key 中指定区间内的元素-1 表示到末尾BLPOP key [key ...] timeout从表头弹出元素若无元素则阻塞等待 timeout 秒timeout0 一直阻塞BRPOP key [key ...] timeout从表尾弹出元素若无元素则阻塞等待 timeout 秒timeout0 一直阻塞使用示例127.0.0.1:6379LPUSHusers123# 左进3 2 1(integer)3127.0.0.1:6379RPUSHusers456# 右进3 2 1 4 5 6(integer)6127.0.0.1:6379LPOPusers# 左出弹出33127.0.0.1:6379RPOPusers# 右出弹出66127.0.0.1:6379LRANGEusers0-1# 查看所有元素1)22)13)44)5List 应用场景常用数据结构组合Stack栈 LPUSH LPOP Queue队列 LPUSH RPOP Blocking MQ阻塞队列 LPUSH BRPOP常见业务场景视频列表、签到列表排队机简化版的 MQ消息队列List 注意事项一个 list 的容量是 2^32-1 个元素大概 40 多亿。但在应用时要注意大 key 问题。list 的底层是一个双向链表对双端的操作性能很高。但是通过索引下标直接操作某一个中间节点的性能就会比较低。✅4. Set 集合 关键理解Set 是无序不重复集合底层使用 listpack小数据量或 hashtable。支持交并差集运算适合做标签、点赞、抽奖等场景。Set 常用操作命令说明SADD key member [member ...]往集合 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 运算操作命令说明SINTER key [key ...]交集运算SINTERSTORE destination key [key ..]将交集结果存入新集合 destination 中SUNION key [key ..]并集运算SUNIONSTORE destination key [key ...]将并集结果存入新集合 destination 中SDIFF key [key ...]差集运算SDIFFSTORE destination key [key ...]将差集结果存入新集合 destination 中Set 应用场景① 微信抽奖小程序-- 点击参与抽奖加入集合 SADD key{userID}-- 查看参与抽奖所有用户 SMEMBERS key -- 抽取 count 名中奖者 SRANDMEMBER key[count]-- 不删除元素可重复中奖 SPOP key[count]-- 删除元素不可重复中奖② 微信/微博点赞、收藏、标签-- 点赞 SADD like:{消息ID}{用户ID}-- 取消点赞 SREM like:{消息ID}{用户ID}-- 检查用户是否点过赞 SISMEMBER like:{消息ID}{用户ID}-- 获取点赞的用户列表 SMEMBERS like:{消息ID}-- 获取点赞用户数 SCARD like:{消息ID}③ 集合运算实现社交关系SINTER set1 set2 → 共同关注的人 SUNION set1 set2 → 朋友圈所有人 SDIFF set1 set2 → 可能认识的人推荐好友④ 社交好友关系实战练习需求张三的好友有李四、王五、赵六李四的好友有王五、麻子、二狗127.0.0.1:6379SADD zs lisi wangwu zhaoliu(integer)3127.0.0.1:6379SADDlswangwu mazi ergou(integer)3-- 计算张三好友有几人127.0.0.1:6379SCARD zs(integer)3-- 计算张三和李四的共同好友127.0.0.1:6379SINTER zsls1)wangwu-- 查询哪些人是张三好友却不是李四好友127.0.0.1:6379SDIFF zsls1)zhaoliu2)lisi-- 查询张三和李四的全部好友127.0.0.1:6379SUNION zsls1)wangwu2)zhaoliu3)lisi4)mazi5)ergou-- 判断李四是否是张三的好友127.0.0.1:6379SISMEMBER zs lisi(integer)1# 返回1是好友-- 将李四从张三的好友列表中移除127.0.0.1:6379SREM zs lisi(integer)1✅5. ZSet 有序集合 关键理解ZSet 与 Java 中的TreeSet类似每个元素关联一个 score 用于排序。底层使用 listpack小数据量 skiplist跳跃表 hashtable。可排序、元素不重复、查询速度快。适合排行榜场景。ZSet 常用操作命令说明ZADD key score member [[score member]...]往有序集合 key 中加入带分值元素已存在则更新 scoreZREM key member [member ...]从有序集合 key 中删除元素ZSCORE key member返回有序集合 key 中元素 member 的分值ZRANK key member获取指定元素的排名从 0 开始按分数从小到大ZREVRANK key member获取指定元素的排名从 0 开始按分数从大到小ZCARD key返回有序集合 key 中元素个数ZCOUNT key min max统计有序集合中分数在给定范围内的元素个数ZINCRBY key increment member为有序集合 key 中元素 member 的分值加上 incrementZRANGE key start stop [WITHSCORES]正序获取有序集合 key 从 start 下标到 stop 下标的元素ZREVRANGE key start stop [WITHSCORES]倒序获取有序集合 key 从 start 下标到 stop 下标的元素ZRANGEBYSCORE key min max [WITHSCORES]按 score 排序后获取指定 score 范围内的元素 注意所有排名默认都是升序如果要降序则在命令的 Z 后面加 REV。例如ZRANK升序排名→ZREVRANK降序排名ZRANGE升序获取→ZREVRANGE降序获取。ZSet 集合运算命令说明ZUNIONSTORE destkey numkeys key [key ...]并集计算ZINTERSTORE destkey numkeys key [key ...]交集计算ZDIFFSTORE destkey numkeys key [key ...]差集计算ZSet 应用场景排行榜--1用户点击新闻增加热度 ZINCRBY hotNews:201908191守护香港 --2展示当日排行前十按热度倒序 ZREVRANGE hotNews:2019081909WITHSCORES --3七日搜索榜单计算合并7天的数据 ZUNIONSTORE hotNews:20190813-201908197\hotNews:20190813 hotNews:20190814... hotNews:20190819 --4展示七日排行前十 ZREVRANGE hotNews:20190813-2019081909WITHSCORES二、扩展数据结构✅6. Bitmap 位图 关键理解Bitmap 本质是 String 的位操作用一个 bit 位来表示某个元素对应的值或状态。最大优势是节省空间适合只有两个状态的数据统计。Bitmap 常用操作命令说明SETBIT key offset value将一个二进制数组的 offset 位置设置成 value0 或 1GETBIT key offset返回一个二进制数组的 offset 位置的值BITCOUNT key [start end [BYTE|BIT]]返回二进制数组中 1 的个数BITPOS key bit [start [end [BYTE|BIT]]]返回 bitmap 中第一个值为 bit 的 offset 位置BITOP AND|OR|XOR|NOT destkey key [key ...]对两个 bitmap 做二进制的与/或/非计算Bitmap 应用场景每日签到--1号用户第100天完成了签到 SETBIT dailycheck:11001-- 统计1号用户的签到次数 BITCOUNT dailycheck:1 -- 统计1号用户第一天签到的时间 BITPOS dailycheck:11优点快速、高效、节省空间。✅7. HyperLogLog 关键理解HyperLogLog 用于统计一个集合中不重复的元素个数基数统计。它不保存具体数据占用空间极小12KB但有约 0.81% 的误差率。典型应用场景统计网站的 UV。HyperLogLog 常用操作命令说明PFADD key element [element ...]添加元素到 HyperLogLogPFCOUNT key [key ...]返回 HyperLogLog 的基数估算值PFMERGE destkey sourcekey [sourcekey ...]将多个 HyperLogLog 合并为一个使用示例-- 添加用户访问记录 PFADD visitlog192.168.65.111192.168.65.112192.168.65.111 -- 统计不同的独立访客UV PFCOUNT visitlog 面试要点HyperLogLog 和 Set 都可以做去重统计但 HyperLogLog 不存储原始数据内存占用仅 12KB适合超大数据量的去重统计如亿级 UV。Set 精确但占内存适合小数据量精确去重。✅8. Geo 地理位置 关键理解Geo 基于 ZSet 实现用于存储地理位置信息经纬度支持距离计算、附近搜索等。底层使用 GeoHash 算法将二维坐标编码为一个字符串。Geo 常用操作命令说明GEOADD key [NX|XX] [CH] longitude latitude member [...]添加一个或多个地点GEOPOS key [member [member ...]]返回地址的经纬度GEODIST key member1 member2 [M|KM|FT|MI]计算两个地点之间的距离GEORADIUS key longitude latitude radius M|KM|FT|MI [...]查询某个经纬度地址附近的地点GEOSEARCH key FROMMEMBER member|FROMLONLAT longitude latitude BYRADIUS radius ...查询某个地点附近的地点Geo 应用场景附近商家推荐获取经纬度坐标https://api.map.baidu.com/lbsapi/getpoint/index.html-- 添加商家地址 GEOADD changsha113.01748928.200454火车站\112.9690328.201195橘子洲\113.01703128.199706赛格广场\113.01700428.197677国储 -- 查询两个地点之间的距离 GEODIST changsha 火车站 橘子洲 M -- 查找火车站附近 2KM 内的景点 GEORADIUSBYMEMBER changsha 火车站2KM WITHdist WITHcoord COUNT4WITHhash三、高级数据结构✅9. Stream 消息流 关键理解Stream 是 Redis 版的 MQ消息队列结合了阻塞队列 pub/sub 的特性。优点是轻量级、低延迟但企业应用中较少直接使用 Redis Stream更多选择专业的 MQ 如 Kafka、RocketMQ 等。了解即可。Stream 常用操作命令说明XADD key [NOMKSTREAM] [MAXLEN|MINID ...] *|id field value [...]往队列的末尾发布一条消息XDEL key id [id ...]删除队列中的一条消息XLEN key获取队列的长度XRANGE key start end [COUNT count]查询队列中的消息Stream 消费者组操作-- 创建队列并添加消息*表示让系统自动生成ID XADD mystream * name loulan name roy name admin -- 查看队列消息- 队列开始 队列结尾 XRANGE mystream - -- 创建消费者组0 从队列头部开始消费$ 从队列尾部开始消费 XGROUP CREATE mystream groupA0-- 消费消息表示从第一条未被消费过的消息消费 XREADGROUP GROUP groupA consumer1 COUNT2STREAMS mystream-- 查看消费者组的消费进度 XPENDING mystream groupA四、SpringBoot 集成 Redis✅10. Maven 依赖与配置Maven 依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency核心配置application.ymlspring:data:redis:host:192.168.65.214port:6379password:123qweasd# ... 更多配置✅11. RestTemplate 快速上手记住一个对象ResourceprivateRedisTemplateString,ObjectredisTemplate;按组操作redisTemplate.opsForValue().xxx// String 类型redisTemplate.opsForSet().xxx// Set 类型redisTemplate.opsForHash().xxx// Hash 类型redisTemplate.opsForList().xxx// List 类型redisTemplate.opsForZset().xxx// ZSet 类型redisTemplate.opsForGeo().xxx// Geo 类型redisTemplate.opsForHyperLogLog().xxx// HyperLogLog 类型redisTemplate.opsForStream().xxx// Stream 类型redisTemplate.opsForValue().setBit()// Bitmap 类型基于 String 注意Bitmap 没有单独的操作类型opsForBit而是通过opsForValue().setBit()来操作因为 Bitmap 本质上是基于 String 的位操作。✅12. RedisTemplate 解决中文乱码BeanpublicRedisTemplateString,ObjectredisTemplate(RedisConnectionFactoryredisConnectionFactory){RedisTemplateString,ObjectredisTemplatenewRedisTemplate();redisTemplate.setConnectionFactory(redisConnectionFactory);// GenericJackson2JsonRedisSerializer jsonSerializer new GenericJackson2JsonRedisSerializer();StringRedisSerializerstringRedisSerializernewStringRedisSerializer();GenericToStringSerializerStringgenericToStringSerializernewGenericToStringSerializer(String.class);// 指定 key 和 value 的序列化方式redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setValueSerializer(genericToStringSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(stringRedisSerializer);redisTemplate.afterPropertiesSet();returnredisTemplate;} 全文总结✅1. 数据结构总览对比数据结构底层实现特点典型场景StringSDS动态字符串基础类型最大 512MB缓存、分布式锁、计数器Hashlistpack / hashtable适合存储对象对象缓存、购物车Listquicklist双向链表有序、可重复栈、队列、阻塞队列Setlistpack / hashtable无序、去重标签、点赞、抽奖、集合运算ZSetlistpack skiplist有序、去重、按分数排序排行榜BitmapString 位操作极省空间1bit/位签到、活跃统计HyperLogLog概率统计算法12KB 固定内存0.81% 误差UV 统计、大基数去重GeoZSet GeoHash地理位置计算附近的人/店铺StreamRax基数树消息队列轻量级 MQ✅2. 面试高频考点String 实现分布式锁SET key value EX 10 NX原子操作注意锁超时和锁释放的安全性Hash vs String 存对象Hash 更节省空间可以针对单个 field 操作但 field 不支持独立过期List 实现的三种结构Stack LPUSHLPOPQueue LPUSHRPOPBlocking MQ LPUSHBRPOPSet 实现社交关系SINTER共同关注、SUNION朋友圈、SDIFF推荐好友ZSet 实现排行榜ZINCRBY增加分数ZREVRANGE倒序获取排名HyperLogLog vs Set 做去重HyperLogLog 省内存但有误差Set 精确但占内存Redis Stream vs 专业 MQStream 轻量级、低延迟但不能持久化、没有 ACK 机制企业级选 Kafka/RocketMQ✅3. 数据结构选择决策树需要排序 ├── 是 → 用 ZSet └── 否 → 需要去重 ├── 是 → 统计基数 │ ├── 是 → HyperLogLog大基数估算 │ └── 否 → Set / ZSet └── 否 → 存对象 ├── 是 → Hash可单字段操作 └── 否 → 有队列特性 ├── 是 → List / Stream └── 否 → String