Redis入门指南之五大核心数据类型解析

📅 2026/8/6 22:57:25
Redis入门指南之五大核心数据类型解析
文章目录前言了解了redis后接下来我们将进入redis的五大核心数据类型的学习以下是我的学习笔记希望可以帮助到大家一、前置基础所有数据都绕不开的Key操作高频通用命令实操示例(工具为Xshell)二、String 字符串最基础的万能类型底层原理高频命令汇总实操示例核心考点原子性适用场景踩坑提醒三、List 列表有序可重复的双向队列底层原理高频命令汇总实操示例适用场景踩坑提醒四、Set 集合无序去重利器底层原理高频命令汇总实操示例适用场景踩坑提醒五、Hash 哈希结构化对象存储首选底层原理高频命令汇总实操示例适用场景踩坑提醒六、Zset 有序集合带权重的排行榜神器底层原理高频命令汇总实操示例适用场景踩坑提醒七、一张表搞定选型五大数据类型对比八、新手高频踩坑面试必考点1. 生产环境避坑2. 面试高频考点一. 为什么Redis单条命令是原子的多条命令怎么保证原子操作答二. List底层为什么选用quicklist不用纯双向链表、也不用纯数组答三. Hash类型 ziplist 和 hashtable 的自动切换条件答四. Zset有序集合底层为什么用跳表不用红黑树答五. Redis五大数据类型区别适用场景答总结一、通用Key操作所有数据共用二、五大数据类型核心速记1. String 字符串2. List 双向链表3. Set 无序集合4. Hash 哈希5. Zset 有序集合三、关键区分口诀前言了解了redis后接下来我们将进入redis的五大核心数据类型的学习以下是我的学习笔记希望可以帮助到大家提示以下是本篇文章正文内容下面案例可供参考一、前置基础所有数据都绕不开的Key操作Redis是典型的Key-Value数据库所有数据都通过「键Key」定位「值Value」。Key本身永远是字符串Value才会区分不同的数据类型。先把通用Key操作搞明白相当于先学会了翻数据库的目录。高频通用命令命令作用注意事项keys *查看当前库所有Key⚠️生产环境严格禁用数据量大时会全量遍历阻塞主线程线上查Key请用SCAN迭代遍历type key查看Key对应的Value数据类型返回string/list/set/zset/hash等exists key判断Key是否存在存在返回1不存在返回0del key删除指定Key连带Value一起删除支持一次删多个Keyexpire key 秒数给Key设置过期时间到期自动删除验证码、临时缓存必备ttl key查看Key剩余存活时间-2已过期/不存在-1永不过期select dbid切换数据库默认16个库编号从0开始dbsize查看当前库Key总数flushdb清空当前库全部数据⚠️ 不可逆操作前务必备份flushall清空所有库全部数据⚠️ 生产环境几乎禁用风险极高实操示例(工具为Xshell)# 查询当前数据库全部key当前无任何数据返回空数组 127.0.0.1:6379 keys * (empty array) # 新增键k1值为eric 127.0.0.1:6379 set k1 eric OK # 新增键k2值为kobe 127.0.0.1:6379 set k2 kobe OK # 新增键k3值为james 127.0.0.1:6379 set k3 james OK # 正确查询所有keyRedis输出无序 127.0.0.1:6379 keys * 1) k3 2) k2 3) k1 # 判断k1是否存在返回1 代表存在 127.0.0.1:6379 exists k1 (integer) 1 # 判断k4是否存在返回0 代表不存在 127.0.0.1:6379 exists k4 (integer) 0 # 查看k1对应value的数据类型结果为string字符串 127.0.0.1:6379 type k1 string # 给k1设置10秒过期时长返回1设置成功 127.0.0.1:6379 expire k1 10 (integer) 1 # 查看剩余存活时间还剩4秒 127.0.0.1:6379 ttl k1 (integer) 4 # 已过期key被自动清除ttl返回-2key不存在/已过期 127.0.0.1:6379 ttl k1 (integer) -2 # 再次确认k1依旧不存在 127.0.0.1:6379 ttl k1 (integer) -2 # 删除键k2返回1成功删除1个键 127.0.0.1:6379 del k2 (integer) 1 # 查看剩余key仅保留k3 127.0.0.1:6379 keys * 1) k3 # 重新创建k1之前过期已销毁这里新建 127.0.0.1:6379 set k1 kobe OK # 清空当前数据库所有键操作不可逆线上严禁随意执行 127.0.0.1:6379 flushdb OK # 清空后无任何key 127.0.0.1:6379 keys * (empty array) # 切换至15号数据库Redis默认0~15共16个独立数据库 127.0.0.1:6379 select 15 OK # 客户端提示符携带[15]代表当前处于15库切回默认0号库 127.0.0.1:6379[15] select 0 OK # 统计当前数据库内key总数量当前数量为0 127.0.0.1:6379 dbsize (integer) 0二、String 字符串最基础的万能类型String是Redis最基础、使用频率最高的类型一个Key对应一个Value。它是二进制安全的普通文本、图片、序列化对象都能存单个Value最大支持512M。底层原理底层是简单动态字符串SDS相比C语言原生字符串它自带长度统计、空间预分配追加、获取长度的效率更高还能兼容二进制数据。高频命令汇总命令作用备注set key value设置键值对Key已存在则覆盖原值get key根据Key取值append key 内容在原值后追加内容返回追加后的字符串长度strlen key获取Value的长度setnx key valueKey不存在时才设置成功分布式锁的基础实现incr key/decr key对数字值自增1/自减1原子操作高并发下不会错乱incrby key 步长/decrby key 步长按指定步长增减mset k1 v1 k2 v2 ...批量设置多个键值对mget k1 k2 ...批量获取多个值setex key 秒数 value设置值的同时设置过期时间存储验证码高频使用set key newValue GET设置新值并返回旧值Redis 6.2 标准写法替代已废弃的GETSET实操示例# 清空当前数据库全部数据不可逆生产环境禁止随便执行 127.0.0.1:6379 flushdb OK # 查看当前库所有key暂无数据返回空数组 127.0.0.1:6379 keys * (empty array) # mset批量设置多个键值对k1v1、k2v2、k3v3 127.0.0.1:6379 mset k1 v1 k2 v2 k3 v3 OK # 展示当前所有keyRedis输出顺序无固定规则 127.0.0.1:6379 keys * 1) k3 2) k2 3) k1 # mget批量读取多个key对应的值 127.0.0.1:6379 mget k1 k2 k3 1) v1 2) v2 3) v3 # msetnx全部key不存在才会批量新增k1已存在整体执行失败返回0 127.0.0.1:6379 msetnx k4 v4 k1 v11 (integer) 0 # 获取keyv4该键未创建返回nil 127.0.0.1:6379 get v4 (nil) # 创建新键v5值为字符串k1 127.0.0.1:6379 set v5 k1 OK # 列出全部现存key 127.0.0.1:6379 keys * 1) v5 2) k3 3) k2 4) k1 # 读取v5对应的值 127.0.0.1:6379 get v5 k1 # 设置键username值为LebronJames 127.0.0.1:6379 set username LebronJames OK # 获取username完整字符串 127.0.0.1:6379 get username LebronJames # getrange截取下标0到5包含两端的子串 127.0.0.1:6379 getrange username 0 5 Lebron # setrange从索引0开始覆盖字符返回修改后字符串总长度11 127.0.0.1:6379 setrange username 0 Sthpen (integer) 11 # 查看覆盖后的字符串 127.0.0.1:6379 get username SthpenJames # setex同时创建键、赋值、设置过期时间键address值chn存活15秒 127.0.0.1:6379 setex address 15 chn OK # 查看address剩余存活8秒 127.0.0.1:6379 ttl address (integer) 8 # 等待超时键自动删除读取返回nil 127.0.0.1:6379 get address (nil) # ttl返回-2代表key不存在/已过期销毁 127.0.0.1:6379 ttl address (integer) -2核心考点原子性incr/decr这类单条命令是原子操作内部的「读取数值→计算→写回」三步是打包执行的中途不会被其他客户端的命令插队。对比Java中的i它分为「读取→计算→赋值」三步多线程并发下会出现计数丢失。这也是Redis能做高并发计数器、秒杀库存扣减的核心原因。适用场景普通数据缓存、页面访问计数器、秒杀库存扣减、短信验证码、分布式锁、简单对象序列化存储。踩坑提醒incr只能操作可转为整数的字符串非数字值会直接报错避免存过大的Value比如几MB的文件会影响Redis性能set默认覆盖原值不确定Key是否存在时请用setnx。三、List 列表有序可重复的双向队列List是单键多值的字符串列表按照插入顺序排序元素可重复。它对列表两端的操作性能极高通过索引访问中间元素性能较差非常适合实现队列、栈结构。底层原理Redis 3.2之后List的底层实现是快速链表quicklist并不是普通的双向链表数据量少时使用压缩列表ziplist连续内存存储节省空间数据量增大后将多个ziplist用双向指针串联起来组成quicklist。这种设计既保证了头尾插入删除的高性能又避免了普通链表指针占用过多内存的问题是空间与性能的权衡。高频命令汇总命令作用备注lpush key v1 v2 v3从列表左侧头部追加元素rpush key v1 v2 v3从列表右侧尾部追加元素lrange key 0 -1查看指定范围的元素0是开头-1是结尾0 -1代表查看全部lpop key从左侧弹出一个元素并返回弹出后元素从列表移除rpop key从右侧弹出一个元素并返回rpoplpush key1 key2将key1最右侧元素移到key2最左侧可用于队列间数据转移lindex key 下标根据索引获取元素从0开始大列表慎用llen key获取列表长度lrem key count value删除匹配元素count0从左删count个count0从右删count0删除所有匹配项lset key 下标 新值替换指定索引位置的元素实操示例# 清空当前数据库所有数据操作不可逆生产慎用 127.0.0.1:6379 flushdb OK # 查询当前库所有键暂无数据返回空数组 127.0.0.1:6379 keys * (empty array) # lpush从列表k1左侧头部插入v1 v2 v3返回列表总长度3 127.0.0.1:6379 lpush k1 v1 v2 v3 (integer) 3 # lrange 0 -1查看列表k全部元素0开头-1代表末尾lpush后进先出顺序v3 v2 v1 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) v1 # rpush从列表k1右侧尾部插入v4 v5 v6列表长度变为6 127.0.0.1:6379 rpush k1 v4 v5 v6 (integer) 6 # 查看完整列表左侧v3开头右侧v6结尾 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) v1 4) v4 5) v5 6) v6 # 再从列表头部插入v6列表长度1变为7 127.0.0.1:6379 lpush k1 v6 (integer) 7 # 头部新增v6列表首位变为v6 127.0.0.1:6379 lrange k1 0 -1 1) v6 2) v3 3) v2 4) v1 5) v4 6) v5 7) v6 # lpop弹出列表最左侧头部第一个元素返回弹出值v6 127.0.0.1:6379 lpop k1 v6 # 头部v6被移除列表更新 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) v1 4) v4 5) v5 6) v6 # rpop弹出列表最右侧尾部元素返回v6 127.0.0.1:6379 rpop k1 v6 # 尾部v6删除后的列表 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) v1 4) v4 5) v5 # 新建列表k2左侧插入s1 s2 s3长度3 127.0.0.1:6379 lpush k2 s1 s2 s3 (integer) 3 # k2列表顺序lpush插入后s3在头部 127.0.0.1:6379 lrange k2 0 -1 1) s3 2) s2 3) s1 # rpoplpush把k1最右侧v5取出插入k2最左侧 127.0.0.1:6379 rpoplpush k1 k2 v5 # k2头部新增v5 127.0.0.1:6379 lrange k2 0 -1 1) v5 2) s3 3) s2 4) s1 # k1尾部v5已被移走 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) v1 4) v4 # lindex 2获取下标为2的元素下标从0开始0v3、1v2、2v1 127.0.0.1:6379 lindex k1 2 v1 # llen统计列表k1总元素个数共4个 127.0.0.1:6379 llen k1 (integer) 4 # linsert before v1 s1在元素v1前面插入s1列表长度变为5 127.0.0.1:6379 linsert k1 before v1 s1 (integer) 5 # 插入后列表展示 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) s1 4) v1 5) v4 # linsert after v2 s2在元素v2后面插入s2长度变为6 127.0.0.1:6379 linsert k1 after v2 s2 (integer) 6 # 插入后完整列表 127.0.0.1:6379 lrange k1 0 -1 1) v3 2) v2 3) s2 4) s1 5) v1 6) v4 # lrem 1 v3从左向右删除1个值为v3的元素返回删除数量1 127.0.0.1:6379 lrem k1 1 v3 (integer) 1 # v3被删除后的列表 127.0.0.1:6379 lrange k1 0 -1 1) v2 2) s2 3) s1 4) v1 5) v4 # lset 1 e2修改下标1位置的元素为e2下标0是v2、下标1是s2 127.0.0.1:6379 lset k1 1 e2 OK # 下标1元素更新为e2 127.0.0.1:6379 lrange k1 0 -1 1) v2 2) e2 3) s1 4) v1 5) v4 # lrange 0 3只查看下标0~3范围内的4个元素 127.0.0.1:6379 lrange k1 0 3 1) v2 2) e2 3) s1 4) v1适用场景简单消息队列、最新浏览记录/评论列表、栈结构、任务排队。踩坑提醒不要用lindex遍历超长列表时间复杂度O(n)数据量大时会阻塞避免列表无限增长记得定期清理历史数据lrem的count参数容易踩坑删除全量请写count0。四、Set 集合无序去重利器Set和List同为集合核心区别是Set元素无序且自动去重。它底层是value为null的哈希表添加、删除、查找的时间复杂度都是O(1)效率极高。底层原理底层是字典dict哈希表实现和Java中HashSet思路一致所有Value都指向同一个空值仅靠Key保证元素唯一性。高频命令汇总命令作用备注sadd key v1 v2 v3向集合添加元素重复元素自动过滤smembers key查看集合所有元素⚠️ 大集合生产慎用建议用SSCAN迭代sismember key 元素判断元素是否在集合中存在返回1不存在返回0O(1)效率scard key返回集合元素个数srem key v1 v2删除指定元素spop key随机弹出一个元素弹出即移除适合随机抽奖srandmember key count随机取出count个元素count0返回不重复元素count0允许重复sinter k1 k2取两个集合的交集共同好友、共同标签场景sunion k1 k2取两个集合的并集sdiff k1 k2取两个集合的差集实操示例# 向集合s1添加v1、v2、v3成功新增3个元素返回新增数量3 127.0.0.1:6379 sadd s1 v1 v2 v3 (integer) 3 # 查看集合全部元素Set无序输出顺序随机 127.0.0.1:6379 smembers s1 1) v3 2) v1 3) v2 # 重复添加已有元素v2集合自动去重无新增返回0 127.0.0.1:6379 sadd s1 v2 (integer) 0 # 集合数据无变化 127.0.0.1:6379 smembers s1 1) v3 2) v1 3) v2 # 判断v1是否在集合内1存在 127.0.0.1:6379 sismember s1 v1 (integer) 1 # 判断v6是否在集合内0不存在 127.0.0.1:6379 sismember s1 v6 (integer) 0 # scard统计集合元素总个数当前3个 127.0.0.1:6379 scard s1 (integer) 3 # 删除v1、v3两个元素成功删除2个返回2 127.0.0.1:6379 srem s1 v1 v3 (integer) 2 # 删除后仅剩余v2 127.0.0.1:6379 smembers s1 1) v2 # 添加v2(重复)、v3、v4、v5、v6仅4个新元素返回4 127.0.0.1:6379 sadd s1 v2 v3 v4 v5 v6 (integer) 4 # 随机弹出2个元素弹出后元素会从集合移除 127.0.0.1:6379 spop s1 2 1) v3 2) v4 # 弹出后剩余元素v2、v5、v6 127.0.0.1:6379 smembers s1 1) v5 2) v2 3) v6 # 随机获取1个元素只查询、不删除集合数据 127.0.0.1:6379 srandmember s1 v2 # srandmember不会移除元素集合保持不变 127.0.0.1:6379 smembers s1 1) v5 2) v2 3) v6 # 将元素v5从s1移动到集合s2移动成功返回1 127.0.0.1:6379 smove s1 s2 v5 (integer) 1 # s1中v5已移走只剩v2、v6 127.0.0.1:6379 smembers s1 1) v2 2) v6 # 向s2添加v2、v6两个新元素返回2 127.0.0.1:6379 sadd s2 v2 v6 (integer) 2 # s2包含移动过来的v5 新增v2、v6 127.0.0.1:6379 smembers s2 1) v6 2) v5 3) v2 # sinter 交集同时存在于s1、s2的元素 v2、v6 127.0.0.1:6379 sinter s1 s2 1) v2 2) v6 # sunion 并集合并两个集合自动去重 127.0.0.1:6379 sunion s1 s2 1) v5 2) v6 3) v2 # sdiff 差集俗称补集保留s2独有、s1不存在的元素仅v5 127.0.0.1:6379 sdiff s2 s1 1) v5适用场景数据去重、共同好友/共同关注、用户标签系统、随机抽奖、黑白名单校验。踩坑提醒元素过多时smembers会一次性返回全部数据可能阻塞Redis集合运算交并差在大数据量下有性能开销注意控制集合大小。五、Hash 哈希结构化对象存储首选Hash是「Key - 字段field - 值value」的嵌套结构相当于Key里面套了一层小Map专门为存储对象设计。对比用String存对象存JSON字符串修改一个字段要全量序列化反序列化拆成多个Key又太零散。用Hash存储修改单个属性非常方便内存占用也更优。底层原理Hash有两种底层存储自动切换字段数量少、值长度短时使用压缩列表ziplist节省内存超过阈值默认512个字段或值大于64字节自动转为哈希表hashtable。阈值可通过配置文件的hash-max-ziplist-entries和hash-max-ziplist-value调整。 注意Redis 4.0之后HSET原生支持批量设置多个fieldHMSET已被官方标记为废弃生产环境请直接使用HSET。高频命令汇总命令作用备注hset key field value存储字段和值支持一次性设置多个field-valuehget key field获取指定字段的值hmget key f1 f2批量获取多个字段的值hexists key field判断字段是否存在hkeys key获取所有字段名hvals key获取所有字段的值hdel key field删除指定字段及对应的值hincrby key field 步长对指定字段做数值增减hsetnx key field value字段不存在时才设置成功实操示例# hset给哈希user新增fieldidvalue1001新增字段数量为1返回1 127.0.0.1:6379 hset user id 1001 (integer) 1 # hget单独获取哈希中id字段的值 127.0.0.1:6379 hget user id 1001 # hmset 批量设置多个字段Redis4.0后hset原生支持批量该命令已废弃推荐用hset替代 127.0.0.1:6379 hmset user username eric age 23 OK # 获取username字段对应值 127.0.0.1:6379 hget user username eric # 获取age字段对应值 127.0.0.1:6379 hget user age 23 # hmget 批量读取多个field的值按传入顺序返回结果 127.0.0.1:6379 hmget user id username age 1) 1001 2) eric 3) 23 # hexists 判断field是否存在1代表存在 127.0.0.1:6379 hexists user id (integer) 1 # hexists 判断address字段0代表不存在 127.0.0.1:6379 hexists user address (integer) 0 # hkeys 获取哈希内所有字段名 127.0.0.1:6379 hkeys user 1) id 2) username 3) age # hvals 获取哈希内所有字段对应的值 127.0.0.1:6379 hvals user 1) 1001 2) eric 3) 23 # hdel 删除age字段成功删除1个返回1 127.0.0.1:6379 hdel user age (integer) 1 # age字段已删除查询返回nil 127.0.0.1:6379 hget user age (nil) # hincrby 对id数值1原子操作返回计算后结果 127.0.0.1:6379 hincrby user id 1 (integer) 1002 # hincrby 对id数值-1 127.0.0.1:6379 hincrby user id -1 (integer) 1001 # hsetnx仅当field不存在时才设置age不存在设置成功返回1 127.0.0.1:6379 hsetnx user age 22 (integer) 1 # username已存在hsetnx不会覆盖返回0 127.0.0.1:6379 hsetnx user username james (integer) 0 # username的值保持不变 127.0.0.1:6379 hget user username eric适用场景用户信息、商品详情、配置项等多属性对象的缓存适合频繁修改单个字段的场景。踩坑提醒字段数量过多会触发ziplist转hashtable内存占用会明显上升Hash不适合存过于复杂的嵌套对象复杂结构仍建议用String存JSON。六、Zset 有序集合带权重的排行榜神器Zset有序集合可以理解为「加强版Set」它同样保证元素唯一但每个元素都会关联一个分数scoreRedis会按照分数自动排序。底层原理Zset底层用两套数据结构配合实现哈希表维护「元素-分数」的映射保证通过元素能O(1)查到分数跳跃表跳表实现元素按分数的有序排列查询效率堪比红黑树但实现更简单、插入删除更灵活。当多个元素分数相同时会按照元素本身的字典序进行二次排序。高频命令汇总命令作用备注zadd key score1 value1 score2 value2添加元素及分数支持NX仅新增、XX仅更新参数zrange key 0 -1按分数升序查看元素加WITHSCORES可连带分数一起返回zrangebyscore key min max查询指定分数区间的元素升序排列zrevrangebyscore key max min按分数降序查询zincrby key 增量 value给指定元素增加分数zrem key value删除指定元素zcount key min max统计指定分数区间的元素个数zrank key value查询元素的升序排名从0开始计数实操示例# zadd 向有序集合user添加4个成员分数成员成功新增4个返回4 127.0.0.1:6379 zadd user 99 kobe 90 durant 95 james 88 curry (integer) 4 # zrange 0 -1按分数从小到大升序展示所有元素只显示成员不带分数 127.0.0.1:6379 zrange user 0 -1 1) curry 2) durant 3) james 4) kobe # 追加 withscores 参数同时返回成员与对应分数 127.0.0.1:6379 zrange user 0 -1 withscores 1) curry 2) 88 3) durant 4) 90 5) james 6) 95 7) kobe 8) 99 # zrangebyscore查询分数区间 95 ~ 100 的所有成员升序输出 127.0.0.1:6379 zrangebyscore user 95 100 1) james 2) kobe # 区间查询并附带分数展示 127.0.0.1:6379 zrangebyscore user 95 100 withscores 1) james 2) 95 3) kobe 4) 99 # zincrby给james的分数增加25返回更新后的分数120 127.0.0.1:6379 zincrby user 25 james 120 # 分数更新后完整升序列表james分数最高排在末尾 127.0.0.1:6379 zrange user 0 -1 withscores 1) curry 2) 88 3) durant 4) 90 5) kobe 6) 99 7) james 8) 120 # zrem 删除成员k成功删除1个返回1 127.0.0.1:6379 zrem user kobe (integer) 1 # 删除kobe后剩余所有成员升序 127.0.0.1:6379 zrange user 0 -1 1) curry 2) durant 3) james # zcount 统计分数区间90~100的成员数量当前仅durant(90)符合返回1 127.0.0.1:6379 zcount user 90 100 (integer) 1 # zrank 查询curry的升序排名排名从0开始 127.0.0.1:6379 zrank user curry (integer) 0 # zrevrangebyscore分数150到1从高到低降序输出区间内成员 127.0.0.1:6379 zrevrangebyscore user 150 1 1) james 2) durant 3) curry # 降序查询并附带每个成员分数 127.0.0.1:6379 zrevrangebyscore user 150 1 withscores 1) james 2) 120 3) durant 4) 90 5) curry 6) 88适用场景各类排行榜游戏积分、内容热度、销量榜、带权重的任务队列、按优先级排序的数据。踩坑提醒分数是双精度浮点数存在微小精度误差业务上注意处理超大范围的排序查询有性能开销尽量分页获取。七、一张表搞定选型五大数据类型对比很多同学学完还是不知道业务里该用哪种整理了一张对比表对照场景直接选就行。数据类型元素特性核心优势典型场景核心操作复杂度String单Key单Value二进制安全最简单、最通用缓存、计数器、分布式锁O(1)List有序、可重复头尾操作快天然支持队列消息队列、最新记录头尾O(1)索引O(n)Set无序、不可重复自动去重支持交并差集去重、共同好友、标签O(1)Hash键值对嵌套结构单字段修改方便省内存用户/商品等对象存储单字段O(1)Zset元素唯一按分数排序自带排序支持排名查询排行榜、优先级队列查找O(logn)选型小口诀单值计数用String有序排队用List去重集合用Set对象存储用Hash排序排行榜直接上Zset。八、新手高频踩坑面试必考点1. 生产环境避坑绝对禁止执行keys *、flushall大Key全量遍历、全库清空都是线上事故级操作避免大Key单个String超过10KB、集合元素超过1万个都算大Key会拖慢Redis甚至阻塞所有临时数据务必设置过期时间防止内存泄漏。2. 面试高频考点一. 为什么Redis单条命令是原子的多条命令怎么保证原子操作答单命令原子根源Redis 核心执行模型是单线程多路IO复用所有读写命令排队串行执行同一时刻只会执行一条完整指令中途不会切换处理其他客户端请求。一条命令的全部步骤读、计算、写一次性执行完毕不会被打断因此天然具备原子性。举例子incr内部取值、自增、回写三步全程独占线程并发不会出现计数错乱。多条命令原子方案单条命令无法满足多操作打包需求两种方案方案1Redis事务multi/exec命令先入队列执行阶段一次性批量运行缺陷事务中途命令报错不会回滚不满足数据库完整原子性。方案2Lua脚本生产推荐一段脚本整体作为单条指令执行完全原子支持判断、循环无事务回滚缺陷。二. List底层为什么选用quicklist不用纯双向链表、也不用纯数组答纯双向链表缺陷每个节点需要前后指针内存碎片多、额外内存开销大大量小数据极度浪费内存。纯数组ziplist压缩列表缺陷扩容、中间插入删除需要整体拷贝数据大数据量时性能暴跌。quicklist 折中方案将多个ziplist压缩列表用双向链表串联。小块连续内存存数据兼顾两点优势小块ziplist节省内存无大量指针冗余链表串联拆分数据插入删除仅操作局部小块不会整体拷贝头尾操作O(1)完美适配队列、浏览记录场景。三. Hash类型 ziplist 和 hashtable 的自动切换条件答Redis Hash存储字段少时用压缩列表ziplist超出阈值自动转为哈希表两个配置控制hash-max-ziplist-entries默认512当hash内field字段数量超过该值切换哈希表hash-max-ziplist-value默认64字节任意一个field的value长度超过该值切换哈希表满足任意一条底层自动从ziplist转为hashtable。ziplist优势连续内存内存占用极小hashtable优势单个字段增删改查O(1)海量字段性能更高。四. Zset有序集合底层为什么用跳表不用红黑树答跳表优势插入、删除、查找平均复杂度 O(logn)和红黑树持平实现逻辑简单无复杂树平衡旋转操作Redis C代码更容易维护范围分页查询排行榜区间性能极佳顺序遍历效率远高于红黑树内存开销可控。红黑树短板增删节点需要频繁旋转平衡代码复杂范围遍历效率差不适合排行榜分页场景。补充Zset底层是「哈希表跳表」组合哈希存元素与score映射O(1)查分数跳表负责排序。五. Redis五大数据类型区别适用场景答String 字符串特性单一key对应单个二进制value支持原子自增、过期场景计数器、验证码、简单缓存、分布式锁。List 列表特性有序、允许重复头尾操作极快底层quicklist场景消息队列、浏览历史、栈结构。Set 集合特性无序、自动去重支持交/并/差集底层哈希表场景用户标签、共同好友、随机抽奖、黑名单。Hash 哈希特性key下嵌套field-value适合对象场景用户/商品多属性缓存单独修改某个字段。Zset 有序集合特性元素唯一绑定score自动排序跳表实现场景热度排行榜、积分排名、带权重任务队列。总结一、通用Key操作所有数据共用基础查询keys *查所有键、type key看数据类型、exists key判断是否存在、dbsize统计键总数删除过期del删单个键expire/ttl设置/查看过期时间验证码、临时缓存必备库操作select n切换数据库flushdb清当前库、flushall清全部库生产禁用核心特性所有Redis单条命令都是原子操作多线程并发不会错乱二、五大数据类型核心速记1. String 字符串结构一个key对应一个二进制value最大512M核心命令set/get、incr/decr原子自增、mset/mget批量操作、setex带过期底层简单动态字符串适用计数器、验证码、简单缓存、分布式锁2. List 双向链表结构有序可重复列表头尾操作极快中间查询慢底层quicklist核心命令lpush/rpush头尾添加、lpop/rpop弹出、lrange查看全部、llen统计长度适用消息队列、最新浏览记录、栈/队列结构3. Set 无序集合结构无序、自动去重底层哈希表O(1)读写核心命令sadd添加、smembers查看、交集/并集/差集、spop随机抽取适用数据去重、共同好友、随机抽奖、黑白名单4. Hash 哈希结构key→field-value嵌套结构底层ziplist/hashtable自适应切换核心命令hset/hget单字段、hmset/hmget批量、hincrby字段自增适用用户、商品等结构化对象缓存修改单个属性无需序列化5. Zset 有序集合结构元素唯一绑定score分数自动排序哈希跳跃表双底层核心命令zadd带分数添加、zrange排行榜、zincrby增减分数适用各类热度排行榜、权重优先级队列三、关键区分口诀存简单文本/计数器用String队列有序重复用List去重无序用Set对象多属性用Hash需要排序排行榜直接上Zset。