news 2026/5/9 7:37:57

购物车该存 Redis 还是 MySQL?架构师教你设计一个“高并发、防丢失”的购物车系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
购物车该存 Redis 还是 MySQL?架构师教你设计一个“高并发、防丢失”的购物车系统

🛒 前言:小小的购物车,大大的坑

在面试中,我最喜欢问候选人一个问题:“设计一个京东/淘宝级别的购物车,数据应该存在哪里?”

  • 回答 A:“存在 Cookie 里,省服务器资源。” ——。用户换个手机登录,购物车空了,体验极差。
  • 回答 B:“存在 MySQL 里,安全。” ——。双 11 千万级并发,每次加购都写库,数据库直接火葬场。
  • 回答 C:“存在 Redis 里,快。” ——对了一半。Redis 挂了怎么办?数据丢失会导致严重的客诉。

真正的购物车系统,是一个**“浏览器 + Redis + MySQL + 消息队列”**的混合架构。今天我们就来拆解这个架构是如何一步步搭建出来的。


🥈 方案一:纯数据库架构 (早期/低流量)

在创业初期,流量不大,直接用 MySQL 也是没问题的。

表结构设计:

CREATETABLE`cart_item`(`id`bigintNOTNULLAUTO_INCREMENT,`user_id`bigintNOTNULLCOMMENT'用户ID',`sku_id`bigintNOTNULLCOMMENT'商品ID',`count`intNOTNULLCOMMENT'数量',`checked`tinyintDEFAULT1COMMENT'是否勾选',`update_time`datetime,PRIMARYKEY(`id`),UNIQUEKEY`idx_user_sku`(`user_id`,`sku_id`));

致命缺陷:
购物车是**“读写极高频”**的业务。
用户反复加减数量、勾选商品,如果每一次操作都去 Update 数据库,数据库的TPS (Transcation Per Second)撑不住。而且这属于“临时数据”,占用大量宝贵的数据库存储空间。


🥇 方案二:纯 Redis 架构 (中等流量)

为了快,我们将数据全部迁移到 Redis。
数据结构选型:Hash

  • Key:cart:{userId}
  • Field:skuId
  • Value: JSON 字符串 (包含数量、勾选状态、加入时间)

Redis 命令演示:

# 添加商品 1001,数量 2HSET cart:88881001"{'count':2, 'checked':1}"# 增加商品数量HINCRBY cart:888810011# 获取购物车所有商品HGETALL cart:8888# 删除商品HDEL cart:88881001

优点:性能极其彪悍,支持 10 万+ QPS。
缺点:Redis 内存贵。且 RDB/AOF 持久化有滞后,极端宕机情况下会丢数据(虽然购物车数据丢失通常可接受,但对于大厂这是 P0 级事故)。


💎 方案三:终极混合架构 (Cookie + Redis + MySQL + MQ)

这是目前主流电商(淘宝、京东)的通用架构。

1. 核心策略
  • 未登录状态:数据保存在客户端Cookie/LocalStorage中。
  • 登录状态:数据保存在Redis中(热数据)。
  • 持久化:通过MQ 异步将 Redis 的变更写入MySQL(冷数据备份,防丢失,做数据分析)。
2. 关键流程:登录合并 (Merge)

这是最复杂的逻辑。当用户在“未登录”时往 Cookie 加了 3 个商品,然后点击“登录”。
系统必须将 Cookie 里的数据 + Redis 里原有的数据进行合并。

架构流程图:

异步持久化
登录合并流程
登录态判断
未登录
已登录
读取临时购物车
读取原有购物车
1. 合并逻辑
2. 清空 Cookie
发送变更消息
削峰填谷
批量写入
RocketMQ / Kafka
DB 同步服务
MySQL 备份库
购物车合并服务
用户登录动作
用户操作
写入 Cookie / LocalStorage
API 网关
操作 Redis Hash

🛠️ 核心代码实战:Redis 封装

我们使用 Spring Boot + RedisTemplate 来实现核心操作。

@ServicepublicclassCartService{@AutowiredprivateStringRedisTemplateredisTemplate;privatestaticfinalStringCART_PREFIX="cart:";/** * 添加购物车 */publicvoidaddCart(LonguserId,LongskuId,Integercount){Stringkey=CART_PREFIX+userId;BoundHashOperations<String,Object,Object>cartOps=redisTemplate.boundHashOps(key);StringskuIdStr=skuId.toString();// 1. 判断商品是否存在if(cartOps.hasKey(skuIdStr)){// 2. 存在则累加数量Stringjson=(String)cartOps.get(skuIdStr);CartItemitem=JSON.parseObject(json,CartItem.class);item.setCount(item.getCount()+count);cartOps.put(skuIdStr,JSON.toJSONString(item));}else{// 3. 不存在则新增CartItemnewItem=newCartItem(skuId,count);cartOps.put(skuIdStr,JSON.toJSONString(newItem));}// 4. 发送 MQ 消息做异步持久化 (伪代码)// producer.send("cart_update_topic", new CartUpdateEvent(userId, skuId));}/** * 登录合并逻辑 */publicvoidmergeCart(LonguserId,List<CartItem>cookieItems){if(CollectionUtils.isEmpty(cookieItems))return;for(CartItemcookieItem:cookieItems){addCart(userId,cookieItem.getSkuId(),cookieItem.getCount());}// 合并完成后,通知前端清除 Cookie}}

🧐 进阶思考:Redis 存满了怎么办?

购物车数据有一个特点:僵尸数据多。很多用户几年前加的商品还在购物车里。
如果所有数据都堆在 Redis,内存会爆炸。

优化策略:LRU + 自动过期

  1. 设置 TTL:给cart:{userId}设置过期时间(例如 30 天)。
  2. 自动续期:每次用户查看购物车或加购时,重置 TTL 为 30 天。
  3. 兜底:如果 Redis Key 过期了(用户 30 天没来了),再次访问时,从MySQL把数据加载回 Redis(缓存预热)。

这样既保证了活跃用户的极速体验,又节省了昂贵的 Redis 内存。


📝 总结

设计购物车系统的 4 个金科玉律:

  1. 读写分离:Redis 抗并发,MySQL 兜底。
  2. 异步写入:使用 MQ 解耦,不要让 DB 拖慢加购速度。
  3. 端云协同:未登录存前端,登录后做合并。
  4. 冷热分离:利用 TTL 清理僵尸购物车。

架构没有最好的,只有最合适的。理解了这套逻辑,你就能轻松应对大多数电商面试题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 13:08:59

豆包手机被微信「拒绝」后,阿里系 APP 被曝也禁止其登陆,如何看待这场「博弈」?核心矛盾是什么?

最近&#xff0c;豆包手机成为了全网热议的焦点。这款备受期待的 AI 手机在发布后短短几天内便遭遇了微信、淘宝等主流应用的封禁&#xff0c;不仅如此&#xff0c;其他阿里系应用也接连宣布禁止该设备登录。这一波波的封杀让无数网友感到震惊&#xff0c;更引发了关于技术、商…

作者头像 李华
网站建设 2026/5/4 19:40:11

字节跳动计算机使用智能体技术架构深度解析

字节跳动计算机使用智能体技术架构深度解析 【免费下载链接】UI-TARS-2B-SFT 项目地址: https://ai.gitcode.com/hf_mirrors/ByteDance-Seed/UI-TARS-2B-SFT 在人工智能从语言理解向自主操作演进的关键节点&#xff0c;字节跳动推出的计算机使用智能体&#xff08;Comp…

作者头像 李华
网站建设 2026/5/8 2:23:52

(新卷)产品模块算法检验(Java、Js、c\c++、python)

产品模块算法检验 在产品配置中&#xff0c;一个配置产品是由多个产品模块(CM)构成&#xff0c;每个CM有自身的算法&#xff0c;且模块间可能存在算法依赖。例如电脑产品是由主板、CPU日、显卡等CM构成。CPU模块(CM1)算法依赖主板模块(CM2)算法&#xff0c;记作CM2<-CM1,算法…

作者头像 李华
网站建设 2026/4/18 3:50:25

RTCP: 统计、同步与网络自适应

RTCP: 统计、同步与网络自适应 本文是 WebRTC 系列专栏的第十三篇,将深入剖析 RTCP 协议的工作原理,包括 Sender/Receiver Report、网络质量反馈以及音视频同步机制。 目录 RTCP 概述RTCP 包类型Sender Report (SR)Receiver Report (RR)丢包、带宽与延迟分析音视频同步 (Lip-S…

作者头像 李华
网站建设 2026/4/23 2:32:31

DuckDB嵌入式分析数据库终极指南:快速上手高性能数据处理

DuckDB嵌入式分析数据库终极指南&#xff1a;快速上手高性能数据处理 【免费下载链接】duckdb DuckDB is an in-process SQL OLAP Database Management System 项目地址: https://gitcode.com/GitHub_Trending/du/duckdb 在当今数据驱动的时代&#xff0c;嵌入式分析数据…

作者头像 李华
网站建设 2026/4/25 9:11:27

深入 Flutter 底层:自定义 RenderObject 实现高性能异形列表项

在 Flutter 开发中&#xff0c;我们常通过组合Container、ClipPath、CustomPaint等组件实现异形 UI&#xff08;如弧形背景、不规则卡片&#xff09;&#xff0c;但在列表场景下&#xff0c;这类方案往往存在重绘频繁、性能损耗大的问题。究其根本&#xff0c;是因为常规组件本…

作者头像 李华