Skip to content

Commit 9ba7fab

Browse files
committed
增加购物车系统设计
1 parent 0273663 commit 9ba7fab

File tree

3 files changed

+233
-8
lines changed

3 files changed

+233
-8
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# 购物车系统怎么设计?
2+
3+
## 1 主要功能
4+
5+
在用户选购商品时,下单前,暂存用户想购买的商品。
6+
7+
购物车对数据可靠性要求不高,性能也无特别要求,在整个电商系统是相对容易设计和实现的一个子系统。
8+
9+
购物车系统的主要功能:
10+
11+
- 把商品加入购物车(后文称“加购”)
12+
- 购物车列表页
13+
- 发起结算下单
14+
- 在所有界面都要显示的购物车小图标
15+
16+
支撑这些功能,存储模型如何设计?
17+
18+
只要一个“购物车”实体。
19+
20+
## 2 主要属性
21+
22+
打开京东购物车页面:SKUID(商品ID)、数量、加购时间和勾选状态
23+
24+
![](http://img.topjavaer.cn/img/20230116134221.png)
25+
26+
“勾选状态”属性,即在购物车界面,每件商品前面的那个小对号,表示在结算下单时,是否要包含这件商品。至于商品价格和总价、商品介绍等都能实时从其他系统获取,无需购物车系统保存。
27+
28+
购物车功能简单,但设计购物车系统的存储时,仍有一些问题需考虑。
29+
30+
## 3 原则
31+
32+
### 3.1 思考
33+
34+
#### 3.1.1 用户未登录,在浏览器中加购,关闭浏览器再打开,刚才加购的商品还在吗?
35+
36+
存在。
37+
38+
若用户未登录,加购的商品也会被保存在用户的电脑。即使关闭浏览器再打开,购物车的商品仍存在。
39+
40+
#### 3.1.2 用户未登录,在浏览器中加购,然后登录,刚才加购的商品还在吗?
41+
42+
存在。
43+
44+
若用户先加购,再登录。登录前加购的商品就会被自动合并到用户名下,所以登录后购物车中仍有登录前加购的商品。
45+
46+
#### 3.1.3 关闭浏览器再打开,上一步加购的商品还在吗?
47+
48+
不存在。
49+
50+
关闭浏览器再打开,这时又变为未登录状态,但是之前未登录时加购的商品已经被合并到刚刚登录的用户名下了,所以购物车是空的。
51+
52+
#### 3.1.4 再打开手机,用相同的用户登录,第二步加购的商品还在吗?
53+
54+
存在。使用手机登录相同的用户,看到的就是该用户的购物车,这时无论你在手机App、电脑还是微信中登录,只要相同用户,看到就是同一购物车,所以第2步加购的商品是存在的。
55+
56+
若不仔细把这些问题考虑清楚,用户使用购物车时,就会感觉不好用,不是加购的商品莫名其妙丢了,就是购物车莫名其妙多出一些商品。
57+
58+
要解决上面这些问题,只要在存储设计时,把握如下
59+
60+
### 3.2 原则
61+
62+
- • 若未登录,需临时暂存购物车的商品
63+
- • 用户登录时,把暂存购物车的商品合并到用户购物车,并清除暂存购物车
64+
- • 用户登录后,购物车中的商品,需在浏览器、手机APP和微信等等这些终端保持同步
65+
66+
购物车系统需保存两类购物车:
67+
68+
- • 未登录情况下的“暂存购物车”
69+
- • 登录后的“用户购物车”
70+
71+
## 4 “暂存购物车”存储设计
72+
73+
### 4.1 保存在客户端or服务端?
74+
75+
若存在服务端,则每个暂存购物车都得有个全局唯一标识,这不易设计。保存在服务端,还要浪费服务端资源。所以,肯定保存在客户端:
76+
77+
- • 节约服务器存储资源
78+
- • 无购物车标识问题每个客户端就保存它自己唯一一个购物车即可,无需标识。
79+
80+
客户端存储可选择不多:
81+
82+
- • Session不太合适。SESSION保留时间短,且SESSION的数据实际上还是保存在服务端
83+
- • Cookie
84+
- • LocalStorage浏览器的LocalStorage和App的本地存储类似,都以LocalStorage代表。Cookie、LocalStorage都可用来保存购物车数据。
85+
86+
选择哪种更好?各有优劣。这场景中,使用Cookie和LocalStorage最关键区别:
87+
88+
- • 客户端、服务端的每次交互,都会自动带着Cookie数据往返,这样服务端可读写客户端Cookie中的数据
89+
- • LocalStorage里的数据,只能由客户端访问
90+
91+
使用Cookie存储,实现简单,加减购物车、合并购物车过程,由于服务端可读写Cookie,这样全部逻辑都可在服务端实现,并且客户端和服务端请求的次数也相对少。
92+
93+
使用LocalStorage存储,实现相对复杂,客户端和服务端都要实现业务逻辑,但LocalStorage好在其存储容量比Cookie的4KB上限大得多,而且不用像Cookie那样,无论用不用,每次请求都要带着,可节省带宽。
94+
95+
所以,选择Cookie或LocalStorage存储“暂存购物车”都行,根据优劣势选型即可:
96+
97+
- • 设计的是个小型电商,Cookie存储实现起来更简单
98+
- • 你的电商是面那种批发的行业用户,用户需加购大量商品,Cookie可能容量不够用,选择LocalStorage更合适
99+
100+
不管哪种存储,暂存购物车保存的
101+
102+
### 4.2 数据格式
103+
104+
都一样。参照实体模型设计,JSON表示:
105+
106+
```
107+
{
108+
"cart": [
109+
{
110+
"SKUID": 8888,
111+
"timestamp": 1578721136,
112+
"count": 1,
113+
"selected": true
114+
},
115+
{
116+
"SKUID": 6666,
117+
"timestamp": 1578721138,
118+
"count": 2,
119+
"selected": false
120+
}
121+
]
122+
}
123+
```
124+
125+
## 5 用户购物车 存储设计
126+
127+
用户购物车须保证多端数据同步,数据须保存在服务端。常规思路:设计一张购物车表,把数据存在MySQL。表结构同样参照实体模型:
128+
129+
![](http://img.topjavaer.cn/img/20230116134240.png)
130+
131+
需在user_id建索引,因为查询购物车表,都以user_id作为查询条件。
132+
133+
也可选择更快的Redis保存购物车数据:
134+
135+
- • 用户ID=Key
136+
- • Redis的HASH=Value,保存购物车中的商品
137+
138+
如:
139+
140+
```
141+
{
142+
"KEY": 6666,
143+
"VALUE": [
144+
{
145+
"FIELD": 8888,
146+
"FIELD_VALUE": {
147+
"timestamp": 1578721136,
148+
"count": 1,
149+
"selected": true
150+
}
151+
},
152+
{
153+
"FIELD": 6666,
154+
"FIELD_VALUE": {
155+
"timestamp": 1578721138,
156+
"count": 2,
157+
"selected": false
158+
}
159+
}
160+
]
161+
}
162+
```
163+
164+
为便理解,用JSON表示Redis中HASH的数据结构:
165+
166+
- • KEY中的值6666是用户ID
167+
- • FIELD存放商品ID
168+
- • FIELD_VALUE是个JSON字符串,保存加购时间、商品数量和勾选状态
169+
170+
读写性能,Redis比MySQL快得多,Redis就一定比MySQL好吗?
171+
172+
### 5.1 MySQL V.S Redis 存储
173+
174+
- • Redis性能比MySQL高出至少一个量级,响应时间更短,支撑更多并发请求
175+
- • MySQL数据可靠性好于Redis,因为Redis异步刷盘,若服务器掉电,Redis有可能丢数据。但考虑到购物车里的数据,对可靠性要求不高,丢少量数据的后果也就是,个别用户的购物车少了几件商品,问题不大。所以,购物车场景,Redis数据可靠性不高这个缺点,不是不能接受
176+
- • MySQL另一优势:支持丰富的查询方式和事务机制,但对购物车核心功能无用。但每个电商系统都有它个性化需求,若需以其他方式访问购物车数据,如统计今天加购的商品总数,这时,使用MySQL存储数据,易实现,而使用Redis存储,查询麻烦且低效
177+
178+
综合比较下来,考虑到需求变化,推荐MySQL存储购物车数据。若追求性能或高并发,也可选择使用Redis。
179+
180+
设计存储架构过程就是不断抉择过程。很多情况下,可选择方案不止一套,选择时需考虑实现复杂度、性能、系统可用性、数据可靠性、可扩展性等。这些条件每一个都不是绝对不可以牺牲的,不要让一些“所谓的常识”禁锢思维。
181+
182+
比如,一般认为数据绝不可丢,即不能牺牲数据可靠性。但用户购物车存储,使用Redis替代MySQL,就是牺牲数据可靠性换取高性能。很低概率的丢失少量数据可接受。性能提升带来的收益远大于丢失少量数据而付出的代价,这选择就值得。
183+
184+
如果说不考虑需求变化这个因素,牺牲一点点数据可靠性,换取大幅性能提升,Redis是最优解。
185+
186+
## 6 总结
187+
188+
- • 购物车系统的主要功能包括:加购、购物车列表页和结算下单
189+
- • 核心实体:只有一个“购物车”实体
190+
- • 至少包括:SKUID、数量、加购时间和勾选状态属性
191+
192+
在给购物车设计存储时,为确保:
193+
194+
- • 购物车内的数据在多端一致
195+
- • 用户登录前后购物车内商品能无缝衔接
196+
197+
除了每个用户的“用户购物车”,还要实现一个“暂存购物车”保存用户未登录时加购的商品,并在用户登录后自动合并“暂存购物车”和“用户购物车”。
198+
199+
暂存购物车存储在客户端浏览器或App,可存放到Cookie或LocalStorage。用户购物车保存在服务端,可以选择使用:
200+
201+
- • Redis存储会有更高的性能,可以支撑更多的并发请求
202+
- • MySQL是更常规通用的方式,便于应对变化,系统扩展性更好
203+
204+
## 思考
205+
206+
既然用户的购物车数据存放在MySQL或Redis各有优劣。那能否把购物车数据存在MySQL,并用Redis缓存?不就兼顾二者优势?若可行,如何保证Redis中的数据和MySQL数据一致性?
207+
208+
用Redis给购物车库做缓存,技术可行。但考虑:
209+
210+
- 值得吗?每个人的购物车都不一样,所以这个缓存它的读写比差距不会很大,缓存命中率不会太高,缓存收益有限,为维护缓存,还会增加系统复杂度。所以我们就要自行权衡一下,是不是值得的问题。除非超大规模系统,否则没必要设置这缓存
211+
- 若非要做这样一个缓存,用什么缓存更新策略?
212+
213+
214+
215+
> 参考:https://mp.weixin.qq.com/s/3P_f_Vua8rwsGOHrxWubSg

docs/learn/ghelper.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 科学上网教程
2+
3+
4+
5+
## Ghelper插件
6+
17
**Ghelper是一款谷歌浏览器插件,用于访问google。**
28

39
第一步:下载并安装**Chrome浏览器**
@@ -52,9 +58,13 @@ Ghelper可以在google play商店进行下载,需要访问google商店,无
5258

5359
**至此安装全部结束。**
5460

61+
## lantern
62+
63+
具体下载方式和操作指引见:https://github.com/getlantern/lantern
64+
5565

5666

57-
> 最后给大家分享一个Github仓库,上面有大彬整理的**300多本经典的计算机书籍PDF**,包括**C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生**等,可以star一下,下次找书直接在上面搜索,仓库持续更新中~
67+
> 最后给大家分享一个Github仓库,上面有大彬整理的**300多本经典的计算机书籍PDF**,包括**C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、架构、分布式、微服务、机器学习、编程人生**等,可以star一下,下次找书直接在上面搜索,仓库持续更新中~
5868
5969
![](http://img.topjavaer.cn/img/Image.png)
6070

docs/zsxq/introduce.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ APP端页面如下(建议大家**使用APP**,因为APP布局更加美观,
2626

2727
目前大彬的学习圈已经积累了很多优质内容了,像**Java面试手册完整版、高频场景设计题目、LeetCode刷题笔记**等。
2828

29-
![](http://img.topjavaer.cn/img/image-20230102151744058.png)
30-
3129
![](http://img.topjavaer.cn/img/image-20230115162250752.png)
3230

31+
![](http://img.topjavaer.cn/img/image-20230102151744058.png)
32+
3333
此外学习圈还积累了很多的**优质学习资源**,包括**计算机基础、Java项目、进阶知识、实战经验总结、优质书籍、笔试面试资源**等等,可以说非常全面了。
3434

35-
![](http://img.topjavaer.cn/img/image-20230112084548339.png)
35+
![](http://img.topjavaer.cn/img/20230116133239.png)
3636

3737
在这里可以找到大部分你想要的**学习资源**,而且这里有一群和你一样志同道合的小伙伴,可以一起提升编程能力、交流学习心得、分享经验、拿更好的Offer!
3838

39-
## 谁适合加入【大彬的学习圈】?
39+
## 谁适合加入的学习圈
4040

4141
1. **非科班转码**或者计算机小白,没有一个完善的学习路线规划;
4242
2. 即将参与校招、实习面试,需要一个引路人;
@@ -51,7 +51,7 @@ APP端页面如下(建议大家**使用APP**,因为APP布局更加美观,
5151

5252
如果你加入了,希望你也能跟像球友们一样**每天坚持打卡学习,为未来奋斗**~
5353

54-
![](http://img.topjavaer.cn/img/星球优惠券-公众号推文.png)
54+
![](http://img.topjavaer.cn/img/星球优惠券-私聊.png)
5555

5656
## 学习圈能提供什么?
5757

@@ -129,7 +129,7 @@ APP端页面如下(建议大家**使用APP**,因为APP布局更加美观,
129129

130130
学习圈有个**置顶的学习资源汇总贴**,包含了近**1000G**的学习资料,是大彬进入互联网行业几年来的积累,从**计算机基础到高阶架构资料**,基本每个阶段都有配套的资料,而且这些资料都是大彬**精心筛选**过的,都是比较优质的资源,可以帮你省去不少搜索的时间!
131131

132-
![](http://img.topjavaer.cn/img/image-20230112082324492.png)
132+
![](http://img.topjavaer.cn/img/20230116133239.png)
133133

134134
![](http://img.topjavaer.cn/img/image-20221229145455706.png)
135135

@@ -173,4 +173,4 @@ APP端页面如下(建议大家**使用APP**,因为APP布局更加美观,
173173

174174
PS:如果加入学习圈之后觉得不合适,**支持3天内全额退款**~
175175

176-
![](http://img.topjavaer.cn/img/星球优惠券-公众号推文.png)
176+
![](http://img.topjavaer.cn/img/星球优惠券-私聊.png)

0 commit comments

Comments
 (0)