当前位置:首页 > 问答 > 正文

Redis哈希怎么用来处理数据,聊聊redis里哈希的那些事儿

(主要参考自Redis官方文档对哈希数据结构的介绍,以及《Redis实战》一书中关于哈希类型的应用场景分析)

Redis里的哈希,你可以把它想象成一个小型仓库,或者一个抽屉柜,它不像字符串(String)那样只能存一个简单的值,哈希能让你在一个键(key)下面,存放好多对“字段-值”(field-value),这就像是给你的主要物品(key)贴上了各种标签(field),每个标签都对应一个具体的说明(value)。

哈希的基本操作:像管理抽屉一样管理数据

假设我们现在要用一个Redis哈希来存一个用户的信息,这个用户的ID是user:1000,我们把这个ID当作整个哈希的键(key),这个用户的名字、年龄、邮箱,就可以作为字段(field)存进去。

Redis哈希怎么用来处理数据,聊聊redis里哈希的那些事儿

  • 存数据: 就像往抽屉里放东西。

    • HSET user:1000 name "小明":在user:1000这个抽屉里,贴上一个叫name的标签,写上“小明”。
    • 你可以一条条地放:HSET user:1000 age 25HSET user:1000 email "xiaoming@example.com"
    • 也可以一次性放好几样:HMSET user:1000 name "小明" age 25 email "xiaoming@example.com"
  • 取数据: 就像从抽屉里找东西。

    • HGET user:1000 name:这会直接告诉你name标签下写的是“小明”。
    • HMGET user:1000 name age:这会一次性把nameage两个标签下的值都拿出来。
    • HGETALL user:1000:这是最厉害的,它会把整个抽屉里的所有东西,包括所有标签和对应的值,统统给你展示出来。
  • 其他实用操作:

    Redis哈希怎么用来处理数据,聊聊redis里哈希的那些事儿

    • HDEL user:1000 email:觉得邮箱这个标签没用了?用这个命令把它从抽屉上撕掉。
    • HKEYS user:1000:不想看具体内容,只想看看这个抽屉里都贴了哪些标签(字段名),用这个。
    • HLEN user:1000:想快速知道这个抽屉里一共有多少样东西(字段数量),用这个。

哈希为啥好用?省地方、高效率

你可能会问,我也可以用普通的字符串来存啊,比如用user:1000:nameuser:1000:age这样的键不也行吗?没错,但哈希有两个特别大的好处:

  1. 节省内存空间: Redis在内部优化了哈希的存储方式,如果你把同一个对象的不同属性拆分成一大堆独立的字符串键,每个键都会附带一些额外的管理信息(元数据),这就像给每件小东西都单独包了一个包装盒,很占地方,而哈希是把所有字段和值打包在一起存储,相当于只用了一个大盒子装所有东西,自然就更省内存。(这一点在Redis官方文档关于内存优化的部分有详细说明)

    Redis哈希怎么用来处理数据,聊聊redis里哈希的那些事儿

  2. 操作效率高: 当你需要获取或修改一个对象的多项属性时,使用哈希可以显著减少网络通信次数,比如你想更新用户的年龄和邮箱,用哈希可能只需要一次HMSET命令,但如果用分开的字符串键,你就得执行两次SET命令,意味着两次网络来回,在高并发的场景下,这个差距对性能的影响是很大的。(《Redis实战》在介绍复合数据结构时强调了这一点)

哈希能用在哪儿?场景比你想的要多

哈希的这种“一个key对应一组数据”的特性,让它特别适合用来表示一个对象。

  • 用户信息存储: 就像前面举的例子,这是最经典的用法,把用户的各种资料存成一个哈希,管理起来非常清晰方便。
  • 商品信息缓存: 电商网站里,一个商品有ID、标题、价格、库存、图片链接等多个属性,把这些属性存成一个哈希,键就是product:12345,查询起来飞快。
  • 购物车: 用哈希来做购物车简直是天作之合,可以把用户ID作为键(比如cart:user123),然后把商品ID作为字段(field),购买数量作为值(value),添加商品就是HINCRBY cart:user123 product456 1(给商品456的数量加1),查看整个购物车就是HGETALL cart:user123,非常直观。
  • 配置信息: 系统中可能会有很多配置项,可以把它们分组存成不同的哈希,比如有一个哈希叫config:database,里面存着hostportusername等字段。

需要注意的几个点

哈希虽好,但也不是万能的,用的时候有几点要留心:

  • 不适合无限扩张: 虽然一个哈希理论上能存非常多(超过40亿)的字段-值对,但如果你真的把一个哈希弄得无比巨大,比如存了几十万个字段,那么在执行HGETALL这种操作时,可能会因为一次性返回数据太多而导致客户端阻塞,要根据实际情况合理设计哈希的大小。
  • 没有单独的过期时间: Redis只能给整个哈希键(key)设置过期时间,而不能给哈希内部的某个字段(field)单独设置,比如你不能设置用户的“验证码”字段10分钟后自动过期,而其他字段永久保存,如果需要这个功能,可能得考虑把需要过期的字段单独拿出来用字符串键存储,并设置过期时间。
  • 原子性操作:HINCRBY(给数字值增加指定数值)这样的命令是原子性的,这意味着在多客户端同时操作时,Redis能保证这个命令不会被打断,数据是准确的,这是Redis提供的重要保障。

Redis的哈希是一个功能强大且灵活的数据结构,当你需要把 logically 属于同一个对象的多条信息组织在一起时,优先考虑使用哈希,往往能让你在性能和资源消耗上获得双赢,它就像是你数据工具箱里的一个多格收纳盒,能让你的数据存储变得井井有条。