【场景题】如何设计一个购物车功能?

news2024/11/16 3:37:56

本文参考文章:https://www.hollischuang.com/archives/6998
https://www.woshipm.com/pd/4115447.html
https://zq99299.github.io/note-book/back-end-storage/01/03.html

首先我们要明白:购物车系统在电商系统中的角色是作为用户选购商品和最终下单的桥梁,它主要的功能是暂存用户的购买意向,包括商品信息、数量等。

注意:购物车系统对数据可靠性的要求不是特别高,但它对于用户体验和系统的性能还是有一定要求的。

购物车系统的功能,主要的就三个:

  1. 把商品加入购物车(后文称「 加购 」)
  2. 购物车列表
  3. 发起结算下单,再加上一个在所有界面都要显示的购物车小图标。

支撑购物车的这几个功能,对应的存储模型应该怎么设计?

  • 商品加入购物车:一般,我们在存储的时候,并不需要把商品的所有信息都保存下来,只需要保存一个SKUID就行了,然后再加上数量、时间等字段即可。
{
 "SKUID": "10086",
 "quantity": 2,
 "timestamp": 1666513990
}
  • 购物车列表:在渲染购物车列表时,可以根据SKUID实时从其他系统中获取商品价格、总价、商品介绍等信息,不需要购物车系统来保存。

  • 发起结算下单:在用户发起结算下单时,可以根据购物车中的SKUID和数量等信息,生成订单并传递给订单系统进行处理。

综上所述,购物车系统的存储模型可以设计得相对简单,主要存储SKUID、数量和时间等基本信息,至于商品价格和总价、商品介绍等等可以通过实时查询获取。这样可以降低购物车系统的存储和计算压力,提高系统性能和用户体验。

设计购物车存储时需要把握什么原则?

比如下面这几个问题:

  1. 用户没登录,在浏览器中加购,关闭浏览器再打开,刚才加购的商品还在不在?

  2. 用户没登录,在浏览器中加购,然后登录,刚才加购的商品还在不在?

  3. 关闭浏览器再打开,上一步加购的商品在不在?

  4. 再打开手机,用相同的用户登录,第二步加购的商品还在不在呢?

上面这几个问题是不是有点儿绕?没关系,我们先简单解释一下这四个问题:

  1. 如果用户没登录,加购的商品也会被保存在用户的电脑里,这样即使关闭浏览器再打开,购物车的商品仍然存在。

  2. 如果用户先加购,再登录,登录前加购的商品就会被自动合并到用户名下,所以登录后购物车中仍然有登录前加购的商品。

  3. 关闭浏览器再打开,这时又变为未登录状态,但是之前未登录时加购的商品已经被合并到刚刚登录的用户名下了,所以购物车是空的。

  4. 使用手机登录相同的用户,看到的就是该用户的购物车,这时无论你在手机 App、电脑还是微信中登录,只要是相同的用户,看到是同一个购物车,所以第二步加购的商品是存在的。

所以,上面这四个问题的答案依次是:存在、存在、不存在、存在。

要解决上面这些问题,其实只要在存储设计时,把握这几个原则就可以了:

  1. 如果未登录,需要临时暂存购物车的商品;

  2. 用户登录时,把暂存购物车的商品合并到用户购物车中,并且清除暂存购物车;

  3. 用户登陆后,购物车中的商品,需要在浏览器、手机 APP 和微信等等这些终端中都保持同步。

如何设计「暂存购物车」的存储?

我们先来看下暂存购物车的存储该怎么实现。暂存购物车应该存在 客户端 还是 存在服务端?

如果保存在服务端,那每个暂存购物车都需要有一个全局唯一的标识,这个标识并不太容易设计,并且,存在服务端还要浪费服务端的资源。所以,肯定是保存在客户端好,既可以节约服务器的存储资源,也没有购物车标识的问题,因为每个客户端就保存它自己唯一一个购物车就可以了,不需要标识。

客户端的存储可以选择的不太多:Session、Cookie 和 LocalStorage,其中浏览器的 LocalStorage 和 App 的本地存储是类似的,我们都以 LocalStorage 来代表。

存在哪儿最合适?SESSION 是不太合适的,原因是,SESSION 的保留时间短,而且 SESSION 的数据实际上还是保存在服务端的。剩余的两种存储,Cookie 和 LocalStorage 都可以用来保存购物车数据,选择哪种方式更好呢?各有优劣。

在我们这个场景中,使用 Cookie 和 LocalStorage 最关键的区别是,客户端和服务端的每次交互,都会自动带着 Cookie 数据往返,这样服务端可以读写客户端 Cookie 中的数据,而 LocalStorage 里的数据,只能由客户端来访问。

  • 使用 Cookie 存储
    实现起来比较简单,加减购物车、合并购物车的过程中,由于服务端可以读写 Cookie,这样全部逻辑都可以在服务端实现,并且客户端和服务端请求的次数也相对少一些。

  • 使用 LocalStorage 存储
    实现相对就复杂一点儿,客户端和服务端都要实现一些业务逻辑,但 LocalStorage 的好处是,它的存储容量比 Cookie 的 4KB 上限要大得多,而且不用像 Cookie 那样,无论用不用,每次请求都要带着,可以节省带宽。

所以,选择 Cookie 或者是 LocalStorage 来存储暂存购物车都是没问题的,你可以根据它俩各自的优劣势来选择。比如你设计的是个小型电商,那用 Cookie 存储实现起来更简单。再比如,你的电商是面那种批发的行业用户,用户需要加购大量的商品,那 Cookie 可能容量不够用,选择 LocalStorage 就更合适。

不管选择哪种存储,暂存购物车保存的数据格式都是一样的,参照我们实体模型来设计就可以,我们可以直接用 JSON 表示:

{
    "cart": [
        {
            "SKUID": 8888,
            "timestamp": 1578721136,
            "count": 1,
            "selected": true
        },
        {
            "SKUID": 6666,
            "timestamp": 1578721138,
            "count": 2,
            "selected": false
        }
    ]
}

如何设计「用户购物车」的存储?

接下来,我们再来看下用户购物车的存储该怎么实现。因为用户购物车必须要保证多端的数据同步,所以数据必须保存在服务端。常规的思路是,设计一张购物车表,把数据存在 MySQL 中。这个表的结构同样可以参照刚刚讲的实体模型来设计:
在这里插入图片描述注意,需要在 user_id 上建一个索引,因为查询购物车表时,都是以 user_id 作为查询条件来查询的。

你也可以选择更快的 Redis 来保存购物车数据,以用户 ID 作为 Key,用一个 Redis 的 HASH 作为 Value 来保存购物车中的商品。比如:

{
    "KEY": 6666,
    "VALUE": [
        {
            "FIELD": 8888,
            "FIELD_VALUE": {
                "timestamp": 1578721136,
                "count": 1,
                "selected": true
            }
        },
        {
            "FIELD": 6666,
            "FIELD_VALUE": {
                "timestamp": 1578721138,
                "count": 2,
                "selected": false
            }
        }
    ]
}

这里为了便于你理解,我们用 JSON 来表示 Redis 中 HASH 的数据结构,其中 KEY 中的值 6666 是一个用户 ID,FIELD 里存放的是商品 ID,FIELD_VALUE 是一个 JSON 字符串,保存加购时间、商品数量和勾选状态。

大家都知道,从读写性能上来说,Redis 是比 MySQL 快非常多的,那是不是用 Redis 就一定比用 MySQL 更好呢?我们来比较一下使用 MySQL 和 Redis 两种存储的优劣势:

  1. 显然使用 Redis 性能要比 MySQL 高出至少一个量级,响应时间更短,可以支撑更多的并发请求,「天下武功,唯快不破」,这一点 Redis 完胜。

  2. MySQL 的数据可靠性是要好于 Redis 的 ,因为 Redis 是异步刷盘,如果出现服务器掉电等异常情况,Redis 是有可能会丢数据的。但考虑到购物车里的数据,对可靠性要求也没那么苛刻,丢少量数据的后果也就是,个别用户的购物车少了几件商品,问题也不大。所以,在购物车这个场景下,Redis 的数据可靠性不高这个缺点,并不是不能接受的。

  3. MySQL 的另一个优势是,它支持丰富的查询方式和事务机制,这两个特性,对我们今天讨论的这几个购物车核心功能没什么用。但是,每一个电商系统都有它个性化的需求,如果需要以其他方式访问购物车的数据,比如说,统计一下今天加购的商品总数 ,这个时候,使用 MySQL 存储数据,就很容易实现,而使用 Redis 存储,查询起来就非常麻烦而且低效。

综合比较下来,考虑到需求总是不断变化,还是 更推荐你使用 MySQL 来存储购物车数据。如果追求性能或者高并发,也可以选择使用 Redis。

你可以感受到,我们 设计存储架构的过程就是一个不断做选择题的过程。很多情况下,可供选择的方案不止一套,选择的时候需要考虑实现 复杂度、性能、系统可用性、数据可靠性、可扩展性等等非常多的条件。需要强调的是,这些条件每一个都不是绝对不可以牺牲的,不要让一些 「所谓的常识」禁锢了你的思维。

比如,一般我们都认为数据是绝对不可以丢的,也就是说不能牺牲数据可靠性。但是,像刚刚讲到的用户购物车的存储,使用 Redis 替代 MySQL,就是牺牲了数据可靠性换取高性能。我们仔细分析后得出,很低概率的情况下丢失少量数据,是可以接受的。性能提升带来的收益远大于丢失少量数据而付出的代价, 这个选择就是划算的。

如果说不考虑需求变化这个因素,牺牲一点点数据可靠性,换取大幅性能提升,选择 Redis 才是最优解。

总结

今天我们讲了购物车系统的存储该如何设计。

购物车系统的主要功能包括:加购、购物车列表页和结算下单。核心的实体就只有一个 「购物车」实体,它至少要包括:SKUID、数量、加购时间和勾选状态这几个属性。

在给购物车设计存储时,为了确保购物车内的数据在多端保持一致,以及用户登录前后购物车内商品能无缝衔接,除了每个用户的 「用户购物车」之外还要实现一个 「暂存购物车」保存用户未登录时加购的商品,并在用户登录后自动合并「暂存购物车」和「用户购物车」。

暂存购物车存储在客户端浏览器或者 App 中,可以选择存放到 Cookie 或者 LocalStorage 中。用户购物车保存在服务端,可以选择使用 Redis 或者是 MySQL 存储,使用 Redis 存储会有更高的性能,可以支撑更多的并发请求,使用 MySQL 是更常规通用的方式,便于应对变化,系统的扩展性更好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1490940.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter中的三棵树

Widget Tree: 页面配置信息。 Element Tree: Widget tree的实例化对象,创建出renderObject,并关联到element.renderobject属性上,最后完成RenderObject Tree的创建。 RenderObject Tree:完成布局和图层绘制…

Unity2013.1.19_DOTS_Burst compiler

Unity2013.1.19_DOTS_Burst compiler DOTS是一种新产品,现在尚在起步阶段。由于它处于持续发展中,随着我们努力使其达到最佳状态,您将看到API会不断演变和日趋成熟。 DOTS包含以下元素: 实体组件系统(ECS) - 提供使用面向数据的…

有个朋友被骗了,大家要擦亮眼睛

1.引言 大家好,我是Leo哥🫣🫣🫣,昨天凌晨有个粉丝朋友找到Leo哥,咨询一些问题,现在的朋友们真卷呐,大半夜还在挑灯夜战。可无奈Leo哥12点之前已经睡了,身体为重&#xf…

云服务器2核4G能支持多少人同时访问?2核4G5M并发量评测

腾讯云轻量应用服务器2核4G5M配置一年优惠价165元、252元15个月、三年756元,100%CPU性能,5M带宽下载速度640KB/秒,60GB SSD系统盘,月流量500GB,折合每天16.6GB流量,超出月流量包的流量按照0.8元每GB的价格支…

安装ProxySQL,教程及安装链接(网盘自提)

一、网盘下载,本地直传 我网盘分享的是proxysql-2.5.5-1-centos8.x86_64.rpm,yum或者dnf直接安装就行 提取码:rhelhttps://pan.baidu.com/s/1nmx8-h8JEhrxQE3jsB7YQw 官方安装地址 官网下载地址https://repo.proxysql.com/ProxySQL/ 二、…

[项目设计] 从零实现的高并发内存池(三)

🌈 博客个人主页:Chris在Coding 🎥 本文所属专栏:[高并发内存池] ❤️ 前置学习专栏:[Linux学习] ⏰ 我们仍在旅途 ​ 目录 4.CentralCache实现 4.1 CentralCache整体架构 4.2 围绕Span的相关设计…

从0到1入门C++编程——09 STL、string容器、vector容器、deque容器

文章目录 一、标准模板库STL二、容器算法迭代器应用1、遍历容器中整型数据2、遍历容器中自定义数据类型3、容器中嵌套容器 三、string容器1、构造函数2、赋值操作3、字符串拼接4、查找和替换5、字符串比较6、字符访问与存取7、插入和删除8、子串 四、vector容器1、构造函数2、赋…

灯丝灯双通道低过温高压线性恒流芯片SM2082ED的应用及特性解析

双通道低过温高压线性恒流芯片是一种电子芯片,它具有双通道设计,可以在高电压条件下工作,并具有低过温特性。这种芯片通常用于需要高电流和高电压的应用,如LED照明、激光器、电机驱动等。 双通道设计意味着该芯片可以同时处理两个…

高级软件开发知识点

流程 算法题简历上项目用到技术、流程、遇到问题HR 准备 常考的题型和回答思路刷100算法题,理解其思想,不要死记最近一家公司所负责的业务和项目: 项目背景、演进之路,有哪个阶段,每个阶段主要做什么项目中技术选型…

【Sql Server】C#通过拼接代码的方式组合添加sql语句,会出现那些情况,参数化的作用

欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Sql Server》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…

想要高薪还想要低要求?想转行做Python自动化测试,我该怎么做?

前言 最近小编连续收到好几个粉丝的私信询问:我年纪上来了,原来的行业做不下去了,想转行还能行吗?我是女生,计算机专业快毕业了,但是不喜欢做开发怎么办?我对编程行业感兴趣,想学编…

社交媒体的未来图景:探索Facebook的数字化之旅

社交媒体已经成为现代社会不可或缺的一部分,其影响力已经深入到人们生活的方方面面。而在众多社交媒体平台中,Facebook无疑是其中的巨头,其数字化之旅更是引领着整个社交媒体行业的发展方向。本文将深入探讨社交媒体的未来图景,以…

Linux中服务端开发

1 创建socket,返回一个文件描述符lfd---socket(); 2 将lfd和IP,PROT进行绑定---bind(); 3 将lfd由主动变成被动监听---listen(); 4 接收一个新的连接,得到一个的文件描述符cfd--accept() --该文件描述符用于与客户端通信 5 while(1) { 接受数据&a…

证明高维度神经网络模型是低纬度神经网络模型的加和

神经网络中矩阵乘法的分解与应用 启发标题:神经网络中矩阵乘法的分解与应用摘要:引言:方法:实验:结论:参考文献:附录1附录2实验数据 启发 理论上 更具矩阵乘法 A[p,mn]B[mn,q]C[p,q] Acat(A[:,…

ChatGPT 4.0 升级指南

1.ChatGPT 是什么? ChatGPT 是由 OpenAI 开发的一种基于人工智能的聊天机器人,它基于强大的语言处理模型 GPT(Generative Pre-trained Transformer)构建。它能够理解人类语言,可以为我们解决实际的问题。 1.模型规模…

K8S实现零宕机实践

越来越多的大厂都在上云、上容器、上K8S编排,K8S和容器云确实帮助我们解决了很多问题。但是,带来方便的同时,也让我们的架构变得更复杂了,更难于依靠“老经验”来解决问题了。虽然我们不用再费力考虑一层的问题,怎么实…

《低代码平台开发实践:基于React》读书心得与实战体验

低代码平台开发实践标题 🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 📘 一、引…

【EI会议征稿通知】第七届交通运输与土木建筑国际学术论坛(ISTTCA 2024)

第七届交通运输与土木建筑国际学术论坛(ISTTCA 2024) 2024 7th International Symposium on Traffic Transportation and Civil Architecture 交通运输是经济发展的先行官,而岩土是发展交通运输网络无法避开的话题。将传统的土木工程技术与先…

Linux 设置快捷命令

以ll命令为例: 在 Linux 系统上,ll 命令通常不是一个独立的程序,而是 ls 命令的一个别名。 这个别名通常在用户的 shell 配置文件中定义,比如 .bashrc 或 .bash_aliases 文件中。 要在 Debian 上启用 ll 命令,你可以按…

Hello World!第一个labview程序

软件版本: labview myrio 2021英文版 因为没有找到中文版的,据说是myrio没有中文版本 实验内容: 文本显示,程序界面输入任意文本,然后运行程序 在前面板显示出输入的文本 以下为具体步骤: 第一步&…