[TOC] #### 1. Hash 类型 --- Redis 的 Hash(哈希)是最常用的数据库结构之一,特别适合存储 “对象型数据” 在 Redis 中,Hash = key 对应一个 “字段、值” 的集合,数据结构示例(类似 JavaScript 的一组普通数据对象): ```plaintext user:1001 -> { name: "Tom", age: "18", email: "xxx@qq.com" } ``` 为什么用 Hash ? + 节省内存(比 String JSON 更优) + 支持局部更新(不用整条修改) + 结构清晰(字段级别操作) 相比于将整个对象序列化为 JSON 字符串存入 String 类型,Hash 类型允许你独立读写对象中的某个属性,这在处理用户信息、商品详情等场景时非常高效。所以,当需要存储一个对象数据的时候,推荐使用 Hash 类型存储。 Hash 的结构是:`Key -> {Field -> Value}` + Key:Redis 的主键,通常命名为:`对象类型:id`,例如:`user:1001` + Field:对象的属性名,例如:name、age + Value:对象的属性值,例如:liang、25 #### 2. 常用命令 --- 为了方便快速上手,整理了最常用的 Hash 命令: | 命令 | 功能描述 | 示例 | | ------------ | ------------ | ------------ | | hset | 设置单个/多个字段值 | `hset user:1 name 'liang' age 20` | | hget | 获取单个字段值 | `hget user:1 name` | | hmget | 获取多个字段值 | `hmget user:1 name age` | | hgetall | 获取所有字段和值 | `hgetall user:1` | | hdel | 删除一个或多个字段 | `hdel user:1 age` | #### 3. 基础用法 --- ##### 新增与修改(hset) `hset` 命令非常灵活,可以设置单个或多个字段,如果字段存在则更新,不存在则新增 ```bash # 设置单个字段 hset user:1001 name "liang" # 批量设置多个字段 hset user:1001 name "liang" age 25 email "23426945@qq.com" ``` ##### 查询数据(hget / hmget / hgetall) + hget:获取指定字段的值 + hmget:一次获取多个指定字段的值,减少网络开销 + hgetall:获取该 key 下所有的字段和值,返回结果是一个列表(字段1,值1,字段2,值2...) ```bash # 获取单个字段的值 hget user:1001 name # 获取多个字段的值 hmget user:1001 name age # 获取全部字段和值 hgetall user:1001 ``` 避坑指南: + 慎用 hgetall:如果 hash 中包含很多字段,它会遍历所有数据,可能导致 Redis 进程阻塞 + 控制字段数量:虽然 hash 能存很多数据,但是建议单个 hash 的字段数不要过大(例如超过 1000),否则容易从 Ziplist 转换为 Hashtable,导致内存占用激增 ##### 数值运算(hincrby / hincrbyfloat) Hash 类型支持对字段值进行原子性的增减操作,非常适合用于计数器场景(如文章阅读量、商品库存) ```bash # 商品数据 hset product:5 id 5 name "进口香蕉" stock 100 price 98 # 库存增加 hincrby product:5 stock 1 # 库存减少(增加一个负数) hincrby product:5 stock -1 # 浮点数运算 hincrbyfloat product:5 price 0.5 ``` ##### 删除与清理(hdel / del) 我们可以删除特定的字段,也可以删除整个 Hash Key ```bash # 用户数据 hset user:1 id 1 name "liang" age 25 # 删除特定字段 hdel user:1 age # 删除整个 Hash Key del user:1 ``` #### 4. 典型应用场景 --- ##### 购物车 购物车是 Hash 最经典的应用场景,数据结构: + Key:`cart:用户ID` + Field :`商品ID` + Value :`商品数量` 这样设计的好处是添加商品、修改数量、删除商品都非常方便,并且不需要读取整个购物车列表 ```bash # 用户 101 将商品 888 加入购物车,数量为 2 hset cart:101 888 2 # 用户 101 将商品 888 的数量再加 1 hincrby cart:101 888 1 # 查看购物车所有商品及数量 hgetall cart:101 ``` ##### 用户信息 相比 JSON 字符串,Hash 存储用户信息更灵活,数据结构: ```plaintext Key:user:info:1001 Field :name、age、birthday、level Value :对应的属性值 ``` 如果只需要更新用户的最后登录时间,只需要修改特定字段,而不需要像 JSON 读取整个字符串,反序列化后修改字段 ```plaintext hset user:info:1001 last_login ... ``` #### 5. 底层原理与性能优化 --- Redis 为了节省内存,为 Hash 设计了两种底层编码方式: Ziplist(压缩列表): + 条件:当 Hash 中字段数量较少(默认 < 512 个)且所有字段值的长度(默认 < 64 字节)都很小时 + 特点:内存占用极低,数据紧凑存储 Hashtable(哈希表): + 条件:当不满足 Ziplist 的条件时(字段多或值大) + 特点:读写时间复杂度稳定为 O(1),但内存占用相对较高