基于本文回答
0
评论

购物车数据在Redis中一般用哪种数据结构存储?如果商品属性非常多,Hash和String哪种更好?

知识点图片

在Redis中实现购物车功能,数据结构的选型非常关键。针对你的问题,我分两部分为你详细解答。

一、 购物车数据在Redis中一般用哪种数据结构?

业界最主流、最标准的做法是使用 Hash(哈希)

为什么是 Hash?

购物车的核心数据模型其实非常简单:“哪个用户 -> 选了哪个商品 -> 买了多少个”
这个模型与 Redis 的 Hash 结构完美契合:

  • Keycart:user:{user_id} (代表某个用户的购物车)
  • Fieldsku_id (代表商品ID)
  • Valuequantity (商品的数量,或者包含数量和添加时间的简单JSON字符串)

Hash 结构的优势:

  1. 增删改查极为方便
    • 添加商品/修改数量:HSET cart:user:1001 sku:10086 1
    • 增加商品数量(如点击“+”号):HINCRBY cart:user:1001 sku:10086 1
    • 删除某个商品:HDEL cart:user:1001 sku:10086
    • 获取购物车所有商品:HGETALL cart:user:1001
    • 获取购物车商品种类数:HLEN cart:user:1001
  2. 性能极高:对单个商品的修改不需要拉取整个购物车的数据,避免了并发修改时的冲突(Race Condition)。

二、 如果商品属性非常多,Hash 和 String 哪种更好?

这里需要先纠正一个架构设计上的常见误区:不要在购物车 Redis 中存储大量的商品属性!

在分布式系统中,正确的做法是“购物车只存关系,不存详情”

  • 购物车只存sku_id数量(最多加一个勾选状态或加入时间)。
  • 大量的商品属性(名称、图片、价格、规格参数等)应该存在单独的商品缓存(Product Cache)中。
  • 读取时:应用层先从购物车取出 sku_id 列表,再通过批量查询(如 MGET管道 Pipeline)从商品缓存中查出详情,在内存中进行拼装。

但如果我们抛开购物车,单从“缓存具有大量属性的商品对象”这个角度来看,String 和 Hash 哪个更好呢?

这取决于你的 数据结构特点业务操作模式

1. 推荐使用 String (存 JSON) 的场景:

  • 数据结构复杂/嵌套:如果商品属性里包含数组、多层对象(例如:{"tags":["new", "hot"], "specs":{"color":"red", "size":"L"}}),Hash 很难优雅地存储这种嵌套结构,而 JSON 一目了然。
  • 总是整体读取:如果每次展示商品,都需要把图片、名字、价格、规格全部展示出来,直接 GET 一个 JSON 字符串并在应用层反序列化,效率非常高。
  • 属性极少单独修改:商品信息(除了库存)通常是运营后台修改的,修改频率低,且通常是整体覆盖更新。
  • 缺点:如果只想修改其中一个字段(比如只改一下价格),需要把整个 JSON 取出来,修改后再重新 SET 回去,并发修改时容易相互覆盖(需要配合乐观锁或Lua脚本)。

2. 推荐使用 Hash 的场景:

  • 数据是扁平的:属性都是简单的 Key-Value 关系。
  • 频繁发生“局部修改”:如果你经常需要只更新商品的某一个属性,而不想拉取其他 50 个无用的属性。使用 HSET product:10086 price 99 可以节省大量的网络带宽和序列化开销。
  • 需要对某个数值属性做原子加减:比如单独针对商品的“销量”、“浏览量”进行 HINCRBY 操作。
  • 缺点:如果每次都要获取全部几十个属性,HGETALL 的性能略逊于直接 GET 一个 String。

3. 终极解决方案:RedisJSON (如果你使用的是较新版本的 Redis)

如果你使用的是 Redis 6.0+ 并安装了 RedisJSON 模块,那么你可以直接以 JSON 格式存储 String,同时又具备 Hash 的局部修改能力。

  • 你可以存入复杂的嵌套 JSON。
  • 你可以单独获取或修改 JSON 中的某一个深层节点:JSON.SET product:10086 $.specs.color '"blue"'
    这种方式结合了 String 和 Hash 的所有优点。

总结建议

  1. 购物车本身:使用 Hash(Key是用户,Field是商品ID,Value是数量/简单JSON)。
  2. 商品详情缓存
    • 如果你需要高频修改某个具体属性(如库存、浏览量),使用 Hash
    • 如果你只是做商品展示,属性层级复杂且基本是整体读取,使用 String (JSON)
    • 如果环境允许,使用 RedisJSON 是最优解。
右滑查看面试常问