[TOC] #### 1. 前言 --- 上一讲用 String 存了一个 JSON 对象: ```bash set user:1001 '{"name":"zhangsan","age":25}' ``` 能用,但有个问题,如果你只想改一下 age 的值,怎么办 ? 得先把整个 JSON 取出来,解析,改 age,再序列化成 JSON 存回去 字段多了,这个操作又蠢又慢,Hash 就是来解决这个问题的 #### 2. Hash 的结构 --- 一个 key 下面可以存多个字段,每个字段有独立的值 ```bash hset user:1001 name liang age 25 city beijing # 往 hash 数据中添加多个字段 hget user:1001 name # "liang" hgetall user:1001 # 全部字段 ``` 改 age,其它字段完全不受影响(不用取出来再存回去): ```bash hset user:1001 age 26 ``` 底层编码: + 字段少(默认 ≤ 128 个)且每个值短(默认 ≤ 64 字节)→ ziplist,紧凑省内存 + 超过了 → hashtable,O(1) 查找,但更占内存,一般不用手动调,Redis 会自动切换 #### 3. Hash vs String 存对象 --- | 对比 | String 存 JSON | Hash | | ------------ | ------------ | ------------ | | 读单个字段 | 取整个 JSON 再解析 | 直接 hget | | 改单个字段 | 取 -> 改 -> 存 | 直接 hset | | 网络开销 | 每次传整个 JSON | 只传需要的字段 | 什么时候用 String ?答:字段少、经常整体读写,比如存一个配置项、一个 Token 什么时候用 Hash?答:字段多、经常改单个字段,比如用户信息、商品详情 #### 4. 应用场景:购物车 --- 一个 Hash 就是一个购物车,增删改查都有现成命令 ```bash hset cart:user:1001 product:2001 1 # 商品2001,数量1 hset cart:user:1001 product:2002 2 # 商品2002,数量2 hincrby cart:user:1001 product:2001 1 # 数量+1 hdel cart:user:1001 product:2002 # 删除商品 hlen cart:user:1001 # 购物车商品数量 hgetall cart:user:1001 # 查看购物车信息 ``` #### 5. 本文小结 --- 小总结: + Hash 存对象,能单独读写某个字段 + 比 String 存 JSON 灵活得多 + 适合:用户信息、商品详情、购物车 + 底层:字段少用 ziplist,多了自动转 hashtable