当前位置: 首页 > news >正文

【Redis】字符串与哈希Day3(2026年)

写在前面

String和Hash是Redis中最常用的两种数据类型,掌握它们的命令细节和应用场景,能让你在实际开发中游刃有余。今天我们深入探讨这两种类型的核心命令与实战技巧。

文章目录

    • 写在前面
    • 一、String命令详解
      • 1.1 基础SET/GET命令
      • 1.2 带参数的SET命令
      • 1.3 数值操作命令
      • 1.4 字符串操作命令
      • 1.5 批量操作命令
    • 二、String应用场景
      • 2.1 缓存
      • 2.2 计数器
      • 2.3 分布式ID生成
      • 2.4 分布式锁
    • 三、Hash命令详解
      • 3.1 基础操作命令
      • 3.2 字段管理命令
      • 3.3 数值操作命令
      • 3.4 批量迭代命令
    • 四、Hash应用场景
      • 4.1 用户信息存储
      • 4.2 商品信息存储
      • 4.3 购物车实现
    • 五、踩坑提醒:value过大问题
      • 5.1 String类型大value
      • 5.2 Hash类型大value
      • 5.3 如何检测大value
    • 六、命令对比表
      • 6.1 String vs Hash命令对比
      • 6.2 场景选择建议
    • 七、面试高频考点
      • Q1:String和Hash存储对象如何选择?
      • Q2:INCR命令有什么注意事项?
      • Q3:如何实现一个分布式锁?
    • 八、参考资料
    • 九、互动话题

一、String命令详解

1.1 基础SET/GET命令

实际场景:SET/GET是最基础也是最常用的命令,但很多细节你可能不知道。

# 基本设置 set name "redis" # 基本获取 get name # 设置并返回旧值 getset name "new_redis" # 仅当key不存在时设置 setnx name "redis" # 仅当key存在时设置 set name "redis" xx

上述命令中,GETSET常用于原子性更新并获取旧值的场景;SETNX是分布式锁的基础;XX参数表示仅当key存在时才设置。

1.2 带参数的SET命令

# 设置过期时间(秒) set session:token "user_data" ex 3600 # 设置过期时间(毫秒) set session:token "user_data" px 3600000 # 设置过期时间戳(秒) set session:token "user_data" exat 1700000000 # NX参数:仅当key不存在时设置 set lock:order "uuid" nx ex 30 # GET参数:设置新值并返回旧值 set counter 100 get

注意事项

  • EX和PX不能同时使用
  • NX和XX不能同时使用
  • SET key value NX EX seconds 是原子操作,适合实现分布式锁

1.3 数值操作命令

经验之谈:Redis的数值操作是原子的,非常适合高并发计数场景。

# 设置数值 set counter 0 # 自增1 incr counter # 自增指定值 incrby counter 10 # 自增浮点数 incrbyfloat counter 2.5 # 自减1 decr counter # 自减指定值 decrby counter 5
命令说明返回值
INCR自增1自增后的值
INCRBY自增指定整数自增后的值
INCRBYFLOAT自增浮点数自增后的值
DECR自减1自减后的值
DECRBY自减指定整数自减后的值

注意事项

  • 如果key不存在,INCR会先初始化为0再自增
  • 如果value不是整数,INCR会报错
  • INCRBYFLOAT支持科学计数法

1.4 字符串操作命令

# 追加字符串 append name " tutorial" # 获取字符串长度 strlen name # 获取子字符串 getrange name 0 4 # 设置子字符串 setrange name 0 "REDIS"

1.5 批量操作命令

# 批量设置 mset key1 "value1" key2 "value2" key3 "value3" # 批量获取 mget key1 key2 key3 # 批量设置(原子操作,任一失败则全部失败) msetnx key1 "value1" key2 "value2"

注意事项

  • MGET返回的是数组,不存在的key返回nil
  • MSETNX是原子操作,适合需要保证一致性的批量设置

二、String应用场景

2.1 缓存

实际场景:缓存是Redis最常见的用途,能显著提升系统性能。

# 设置缓存(带过期时间) set cache:user:1001 '{"name":"zhangsan","age":25}' ex 3600 # 获取缓存 get cache:user:1001 # 缓存不存在时的处理(伪代码) # if redis.get(key) is None: # data = db.query(...) # redis.set(key, data, ex=3600)

缓存策略对比

策略说明适用场景
Cache Aside先查缓存,不存在再查库读多写少
Write Through写入时同时更新缓存读写均衡
Write Behind先写缓存,异步写库写多读少

2.2 计数器

# 文章阅读量 incr article:1001:views # 用户点赞数 incr user:1001:likes # 获取计数 get article:1001:views # 批量获取多个计数 mget article:1001:views article:1002:views

注意事项

  • 计数器不需要初始化,INCR自动创建
  • 高并发下INCR是原子操作,不会丢失计数

2.3 分布式ID生成

# 每天重置的ID set order:id:20240101 0 # 生成订单ID incr order:id:20240101 # 返回1,订单ID为:20240101000001 # 批量获取ID incrby order:id:20240101 100

2.4 分布式锁

踩坑提醒:分布式锁实现要考虑锁超时、误删等问题。

# 加锁(原子操作) set lock:order:1001 "uuid-xxx" nx ex 30 # 业务逻辑执行... # 释放锁(Lua脚本保证原子性) # if redis.call("get", KEYS[1]) == ARGV[1] then # return redis.call("del", KEYS[1]) # else # return 0 # end

分布式锁注意事项

  1. 设置过期时间,防止死锁
  2. value使用唯一标识,防止误删
  3. 释放锁时验证value,使用Lua保证原子性

三、Hash命令详解

3.1 基础操作命令

实际场景:Hash天生适合存储对象,比String+JSON更灵活。

# 设置单个字段 hset user:1001 name "zhangsan" # 设置多个字段 hmset user:1001 name "zhangsan" age 25 city "beijing" # 获取单个字段 hget user:1001 name # 获取多个字段 hmget user:1001 name age city # 获取所有字段和值 hgetall user:1001 # 获取所有字段名 hkeys user:1001 # 获取所有值 hvals user:1001

3.2 字段管理命令

# 删除字段 hdel user:1001 city # 检查字段是否存在 hexists user:1001 name # 仅当字段不存在时设置 hsetnx user:1001 email "test@example.com" # 获取字段数量 hlen user:1001

3.3 数值操作命令

# 字段自增整数 hincrby user:1001 age 1 # 字段自增浮点数 hincrbyfloat user:1001 salary 1000.5

3.4 批量迭代命令

# 迭代获取字段(适合大Hash) hscan user:1001 0 match "field_*" count 10

四、Hash应用场景

4.1 用户信息存储

经验之谈:用户信息用Hash存储,可以只更新某个字段,比String+JSON更高效。

# 存储用户信息 hmset user:1001 name "zhangsan" age 25 city "beijing" email "zhangsan@example.com" # 只更新年龄 hset user:1001 age 26 # 只获取姓名和邮箱 hmget user:1001 name email # 检查邮箱是否存在 hexists user:1001 email

Hash vs String存储对象对比

对比项Hash存储String+JSON存储
部分读取支持(HGET)需要整体读取
部分更新支持(HSET)需要整体更新
内存占用较小(ziplist)较大
字段查询支持(HEXISTS)需要解析JSON
适用场景字段多、部分访问字段少、整体访问

4.2 商品信息存储

# 存储商品信息 hmset product:2001 name "iPhone 15" price 6999 stock 100 category "phone" # 库存减1 hincrby product:2001 stock -1 # 获取库存 hget product:2001 stock # 获取商品基本信息 hmget product:2001 name price stock

4.3 购物车实现

# 添加商品到购物车 hset cart:user:1001 product:2001 2 hset cart:user:1001 product:2002 1 # 修改商品数量 hset cart:user:1001 product:2001 3 # 获取购物车所有商品 hgetall cart:user:1001 # 删除购物车商品 hdel cart:user:1001 product:2002 # 获取购物车商品数量 hlen cart:user:1001

五、踩坑提醒:value过大问题

踩坑提醒:大value是Redis性能杀手,务必控制value大小!

5.1 String类型大value

问题表现

  • 单个String value超过10KB
  • 网络传输慢,阻塞其他操作
  • 内存碎片增加

解决方案

# 方案1:压缩存储 # 将大对象压缩后存储 set big:object "compressed_data" ex 3600 # 方案2:拆分存储 set user:1001:profile "基本信息" set user:1001:detail "详细信息" set user:1001:settings "设置信息" # 方案3:使用Hash拆分 hmset user:1001 profile "基本信息" detail "详细信息" settings "设置信息"

5.2 Hash类型大value

问题表现

  • 单个Hash字段数超过5000
  • HGETALL操作耗时
  • 内存占用高

解决方案

# 拆分为多个Hash hmset user:1001:basic name "zhangsan" age 25 hmset user:1001:contact email "xxx" phone "xxx" hmset user:1001:address city "beijing" street "xxx" # 使用HSCAN迭代获取 hscan user:1001:basic 0

5.3 如何检测大value

# 使用redis-cli扫描大keyredis-cli--bigkeys# 查看指定key的内存占用redis-cli memory usage keyname# 使用RDB工具分析rdb--commandjson dump.rdb|python analyze.py

六、命令对比表

6.1 String vs Hash命令对比

操作String命令Hash命令
设置值SET key valueHSET key field value
获取值GET keyHGET key field
删除DEL keyHDEL key field
检查存在EXISTS keyHEXISTS key field
自增INCR keyHINCRBY key field num
批量设置MSET k1 v1 k2 v2HMSET key f1 v1 f2 v2
批量获取MGET k1 k2HMGET key f1 f2

6.2 场景选择建议

场景推荐类型理由
简单KV缓存String简单高效
对象存储(字段多)Hash支持部分读写
计数器StringINCR原子操作
分布式锁StringSET NX EX原子操作
购物车Hashfield为商品ID,value为数量
用户SessionString整体存取,带过期时间

七、面试高频考点

Q1:String和Hash存储对象如何选择?

答案

  • 字段少(<5个)且整体访问:选String
  • 字段多或需要部分访问:选Hash
  • 需要设置过期时间:选String(Hash不支持对单个field设置过期)
  • 内存敏感:选Hash(ziplist编码更省内存)

Q2:INCR命令有什么注意事项?

答案

  1. value必须是整数格式,否则报错
  2. key不存在时会初始化为0再自增
  3. 范围是64位有符号整数,超出范围会报错
  4. 是原子操作,高并发下安全

Q3:如何实现一个分布式锁?

答案

# 加锁(原子操作) set lock:resource "uuid" nx ex 30 # 释放锁(Lua脚本保证原子性) eval "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:resource "uuid"

关键点:

  1. 使用SET NX EX原子加锁
  2. value使用唯一标识防止误删
  3. 释放锁时验证value
  4. 设置合理的过期时间

八、参考资料

Redis内存优化指南


九、互动话题

你在项目中遇到过String和Hash选型的困惑吗?有没有因为选错类型导致的性能问题?欢迎在评论区分享你的经验!

下一篇我们将深入探讨List和Set的命令细节与应用场景。

http://www.jsqmd.com/news/915504/

相关文章:

  • 大学生英语竞赛C类词汇题怎么破?这3类高频考点和避坑指南请收好
  • 超越传统基尼系数:用Dagum分解和Python量化区域发展不平衡(以中国省级数据为例)
  • 从G题RockFrog到李超线段树:如何用动态开点解决特殊二次函数最值问题(附__int128防爆指南)
  • 最新fastmoss优惠折扣码开通,fastmoss推荐码TK1000优惠是什么? - 跨境电商卖家出海官方
  • 技术美术避坑指南:三方向映射的法线混合,别再直接Lerp了!
  • Unity VideoPlayer实战避坑:从本地视频到网络流,完整配置流程与常见报错解决
  • 2026南京市防水补漏公司权威推荐:卫生间、阳台、屋顶、地下室、飘窗、外墙漏水,专业防水公司TOP5口碑榜+全维度测评(2026年6月最新深度行业资讯) - 防水百科
  • AI智能体动态竞争评估:从静态测试到模拟市场的新范式
  • XUnity.AutoTranslator:让游戏语言无障碍的智能翻译解决方案
  • CTF密码学入门:如何利用已知子密钥片段逆向破解DES加密(以NepCTF simpleDES为例)
  • 不止是画线:用Vectrosity插件在Unity里制作自定义进度条与技能指示器
  • AD7606采样率上不去?STM32F4 SPI时序详解与定时器中断优化指南
  • 2026年5月荆州黄金回收红黑榜:余生黄金回收(全国连锁)综合评分第一,6家门店完整对比+避坑指南 - 润富黄金珠宝行
  • 智慧树刷课插件终极指南:3分钟解放你的在线学习时间
  • 别再只会用阿里源了!保姆级教程:Ubuntu 20.04/22.04 如何根据网络环境智能选择最快的镜像源
  • 千鸿黄金回收|2026 年 5 月大同黄金回收价透明,全城上门不扣重 - 润富黄金珠宝行
  • 用HBase Java API重构学生选课系统:从关系型数据库迁移的完整实战
  • MoveIt2路径规划总失败?试试这个trac_ik插件:实测setPoseTarget可用性分析与配置心得
  • 2026 杭州全屋定制公司推荐|性价比高、工艺靠谱的本土定制品牌汇总 - 商业新知
  • 从《头号玩家》到你的项目:拆解Unity Cinemachine虚拟相机的5种跟踪模式(3rd Person/Orbital等)
  • 别再乱选Canvas渲染模式了!Unity UI开发中Screen Space - Overlay、Camera、World Space的实战选择指南
  • 用STM32和OLED做个土壤湿度监测仪(附完整代码和接线图)
  • 2026年新疆塑料管道定制源头厂家综合对比:荣华装备科技如何成为西北基建首选 - 企业名录优选推荐
  • 别再花钱买授权了!手把手教你用Docker和开源方案实现USB设备网络共享(附避坑指南)
  • 实测避坑:在Win10/11 21H2企业版中,用组策略搞定域用户无感安装网络打印机(附排错指南)
  • 机器人+AI如何重塑医疗美容:从精准手术到个性化康复的技术融合
  • Scarab:智能模组管理如何让《空洞骑士》游戏体验提升300%
  • 新手避坑指南:用立创EDA从零画一块STM32F103RCT6核心板(附完整原理图/PCB源文件)
  • 日照大学城海鲜面实测排名!5 家硬核对比,包厨子海鲜面稳居 C 位 - 兔兔不是荼荼
  • 高效解决Honey Select 2兼容性问题的专业模组整合方案:HS2-HF Patch深度解析