🎤 面试官:你做过购物车功能吧?说说你们是怎么实现的?
我: 做过,我们平台的购物车其实分两种情况:
- 一种是没登录的时候,你想逛逛、先加个商品看看;
- 一种是登录之后,要把你之前加的东西合并进来,还能跨设备同步。
所以我们是“前端存一部分,后端存一部分”,两边配合着来。
🎤 面试官:没登录的时候,购物车存哪儿?
我: 存浏览器里,用
localStorage。比如用户打开网页,点了“加入购物车”,我们就往
localStorage里写一条:json{ "productId": 1001, "count": 2 }这样就算他关了浏览器再进来,东西还在。
但有个问题——换手机、换浏览器就没了,毕竟数据只在本地。 所以我们一直提醒用户:“登录后购物车更安全”。
🎤 面试官:那登录之后呢?怎么把本地的和服务器的合并?
我: 这是个挺常见的场景,我们是这么处理的:
用户一登录,前端就把
localStorage里的购物车数据发给后端,比如:json[{ "productId": 1001, "count": 2 }]后端收到后,做三件事:
- 查 Redis:看这个用户的购物车里有没有这个商品;
- 去重 + 数量叠加:比如 Redis 里已经有
1001:1,本地又加了1001:2,那就变成3;- 保存到 Redis,同时清掉
localStorage。这样就完成了“本地购物车 → 云端同步”。
而且这个过程对用户是无感的,他登录完刷新一下页面,发现之前加的东西都在,体验就很好。
🎤 面试官:购物车数据存在 Redis,那 Redis 挂了怎么办?
我: 确实怕,但我们也没啥特别高大上的办法,主要是靠“兜底 + 告警”。
- Redis 我们用的是主从 + 哨兵,挂一台机器能自动切,一般小故障扛得住;
- 如果整个 Redis 集群崩了(比如机房断电),那确实购物车数据会丢;
- 但我们做了个降级方案:
- 临时把购物车读写切到数据库(MySQL),虽然慢点,但能用;
- 同时发告警,运维赶紧救火;
- 等 Redis 恢复了,再把数据库里的数据同步回去。
说白了,Redis 不是数据库,我们不指望它 100% 不丢数据,但要有应对预案。
🎤 面试官:购物车里的商品价格变了,或者库存没了,怎么处理?
我: 这个太常见了,尤其是大促的时候,价格调来调去,库存一会儿有、一会儿没。
我们的做法是:
- 购物车里存的是快照信息,不是实时数据。 比如你加商品时价格是 99,哪怕后来涨到 199,购物车里还是显示 99;
- 但下单的时候必须重新校验! 不能说“我加的时候是 99,现在就得按 99 卖”,那商家就亏死了。
所以下单时我们会:
- 查最新价格 —— 如果变了,弹个提示:“亲,价格有调整,是否继续?”
- 查库存 —— 如果没货了,直接提示“该商品已售罄,无法下单”
说白了:购物车可以“骗人”,但下单必须真实。
🎤 面试官:购物车怎么支持批量操作?比如全选、删多个?
我: 我们后端提供了几个接口:
GET /cart:拉整个购物车POST /cart/add:加商品POST /cart/update:改数量POST /cart/delete:支持传多个商品 ID,批量删POST /cart/empty:清空前端点“全选删除”,就调
delete接口,传个数组[1001, 1002, 1003]。后端用 Redis 的
HDEL cart:12345 1001 1002 1003一条命令搞定,很快。而且我们还加了个“最近删除”功能,删了的东西保留 5 分钟,可以一键恢复,防止手滑。
🎤 面试官:购物车数据量大了会不会慢?怎么优化?
我: 确实会,尤其是有些用户往购物车里加了几百个商品,一进页面卡半天。
我们做了几个优化:
- 分页加载:不一口气拉全部,先加载前 20 个,用户往下拉再加载;
- 商品信息缓存:购物车里只存
商品ID + 数量,商品标题、图片、价格这些从 Redis 缓存里批量查,避免反复查数据库;- 过期策略:设置
cart:userId过期时间 30 天,用户 30 天没登录,自动清理,省资源;- 本地缓存加速:用
Caffeine缓存热点用户的购物车,减少 Redis 访问。现在平均响应时间在 100ms 以内,基本感觉不到卡。
🎤 面试官:有没有遇到过什么坑?
我: 有啊,最惨一次是——
我们一开始用 Redis 的
HGETALL把整个购物车拿出来,然后在 Java 里遍历改数据,再HSET写回去。结果有个用户加了 800 多个商品……每次一访问购物车,Redis 直接被打满,CPU 100%,整个系统卡住。
后来我们改了:
- 改成用
HINCRBY直接在 Redis 里加数量;- 删商品用
HDEL传多个 key;- 能在 Redis 里做的操作,绝不拉到 Java 里算。