记忆前分离后:电商项目中的经典问题

请描述一下这个系统?

【回答技巧】

从3个方面来回答这个问题:

|--系统背景及系统概述

|--系统包括的业务模块及主业务流程

|--责任模块

【回答示例】

第一个方面:系统背景及系统概述

优购时尚商城是香港上市公司百丽国际公司为拓宽旗下运动品牌服饰市场而开发的一个专业销售购物网站户外运动装备的网站。

 

第二个方面:系统包括的业务模块及主业务流程

改项目分为前台和后天2大模块:

前台又包含:全部商品分类、运动馆、户外馆、鞋靴馆、女装馆、男装馆、母婴馆、生活馆、会员中心、秒杀、闪团、INNET运动鞋、潮流馆。每一个分类都是对该范围类商品的一些具体分类以及明星商品的展示、新品展示、品牌连接等等。前台还包含用户的登录注册、我的优购、我的订单、公告等模块,主要用于客户下单。结算、收货等一系列购物操作。以及个人中心的个人信息、订单信息的查看和维护。

后台后台包含:商品管理、订单管理、代客下单、支付管理、广告管理、合作伙伴管理、会员管理、权限管理、系统配置、报表管理等模块。

 

第三方面:责任模块

这个系统我主要负责的是商品管理模块的CRUD以及商品的属性管理、商品的上下架、品牌管理、订单管理

前台主要负责商品的主页面展示、商品的筛选、商品详情展示。在商品详情页面采用freemarker页面静态化技术。降低服务器压力减少对服务器的I/O。商品详情页实现了添加购物车和结算功能。购物车根据与项目经理协商采用cookie技术实现。【此处可以加入几种保存方案:1.保存数据库{问题是造成数据库压力倍增} 2.使用cookie{用户更换电脑或浏览器添加购物车商品丢失,但是此网站不考虑}  3.最好解决方案保存到redis数据库。前两个问题全部解决】。提交订单功能可能出现并发问题。原因在于大量用户都可能购买。库存出现不足问题。这里可以插入自己对数据库的理解:锁机制【悲观所:线程等待。效率太低。乐观锁:解决了悲观所的效率问题。可选。但是update语句本身就带锁。所以不用加锁就能解决这个并发修改库存问题】,前台我还负责了个人中心的模块。包括:我的订单、退换货订单、我的收藏、个人资料、收货地址等功能模块。

说说系统的架构?

本系统使用maven进行构建,

将系统分成了技术基础架构模块、前台工程模块、后台工程模块、主工程模块、文件系统工程模块。

扩展问题:

Spring在系统中如何使用?

Spring对控制层、业务层、持久层的bean进行统一管理。

对控制层的action,通过@controller注解,自动组件扫描方式将action在spring容器注册。

对业务层的service,在spring配置文件进行配置,好处是方便系统开发与维护。Spring对业务层进行事务控制。

对持久层的mapper,通过spring与mybatis整合包的mapper扫描器自动扫描编写的mapper。

 

本系统如何用maven开发?

本系统采用maven进行模块划分,将系统分成了核心基础架构模块、前台工程模块、后台工程模块、主工程模块、文件系统工程模块

 

核心基础架构模块:

此模块包括了对spring、mybatis的配置信息

pom.xml中配置jar包的依赖,方便统一管理本项目的jar包依赖。

前台和后台所有业务和数据访问层的编码实现。方便子模块重复调用。

 

前台工程模块:

此模块包括系统前台所用到所有controller。负责调用核心基础模块中的业务方法进行前台数据展示

 

后台工程模块:

此模块包括系统后台所用到所有controller。负责调用核心基础模块中的业务方法进行商家的后台管理

 

主工程模块:

此模块是将各各子模块进行聚合,最终生成一个war包。

 

文件系统工程模块:

次模块用于保存系统的所有文件。包括商品图片、报表模板、企业公告等文件。用于分散服务器I/O提高项目访问效率。

 

扩展问题:

maven仓库是怎么构建?

实际开发在局域网中公司创建了一个maven私服,私服上存放系统所用到的jar包。

本系统实现国际化了吗?是怎么做?

本系统没有实现国际化,本系统是具有中国特色的电商项目,不需要实现国际化

这个系统mybatis是怎么用的?或这个系统持久层如何实现的?

1、mybatis框架

使用mybatis官方出的mybatis与spring整合包将mybatis和spring整合。

 

针对单表的增、删、改、查使用mybatis官方提供的逆向工程,根据数据库表的结构生成mybatis当中的mapper.xml、mapper.java、po及相关的类。在service中直接使用自动生成的mapper接口。

 

针对自动生成的mapper无法满足业务需求时,自定义mapper,一般情况下多表查询需要自定义mapper。

 

Mapper开发完成通过mybatis与spring整合包中的mapper扫描器将mapper在spring容器中进行注册。

 

 

 

扩展问题:(回答问题切莫问什么答什么。自己要发散思维。扩展的回答面试问题)

1、 mapper的扫描器是如何使用的

在spring配置文件配置mapper扫描器,配置项指定扫描的包的路径。

使用扫描器需要遵循一些mapper编写规则:

Mapper.xml和mapper.java在同一个目录,且文件名相同。

Mapper.xml中的statement 的id和mapper.java中的方法名一致。

Mapper.xml中的statement的parameterType和mapper.java中的方法输入参数一致。

Mapper.xml中的statement的resulttype和mapper.java中的方法输出结果类型一致。

这个系统springmvc是怎么用的?

使用springmvc注解开发。

 

1、 对于页面展示类的方法,控制器方法返回string ,string就是逻辑视图名。

2、 对于提交类的方法,控制器方法返回json数据,使用@Responsebody注解将action方法的返回值转为json输出。

Responsebody注解内部使用jackson将java对象转为json

本系统ajax+json具体是怎么做的?action的方法返回的json是如何实现的?

 

ajax+json:页面采用ajax提交,服务端返回是json,

 

页面提交统一采用ajax Form提交方式,使用了jquery提供form组件,在开发时和原始form的post 提交方法配合使用,使用jquery Form组件更能简化开发提高用户体验和开发效率。

 

扩展问题:

系统哪些地方使用到了json?

1、 图片上传返回的相对和绝对路径。方便图片回显和URL保存。

2、 购物车中的最小销售单元的数据保存

3、 权限列表使用json数据表示。

4、 个人中心的省市县联动数据使用json返回

使用json目的:使用json方便客户端页面解析数据。

这个系统的用户认证是怎么实现的?

使用用户名密码认证方式。

 

1、 用户认证

2、 用户身份校验

用户身份校验使用springmvc提供拦截器完成。

 流程:

        builder.deploy();

    }

}

1. 部署流程

2. 查询业务任务
3. 办理任务

项目中哪些功能模块涉及了大数据量访问?你是如何解决的?

系统前台是互联网上的用户访问的,会有大量用户来访问。
假定有1w个人打开你的网站来订商品,问你如何解决并发问题(可扩展到任何高并发网站要考虑的并发读写问题)
问题,1w个人来访问,商品没出去前要保证大家都能看到有商品,不可能一个人在看到商品的时候别人就不能看了。到底谁能抢到,那得看这个人的“运气”(网络快慢等)
其次考虑的问题,并发,1w个人同时点击购买,到底谁能成交?总共只有一张商品。

Update eb_sku t sett.stock = t.stock – 1 where t.sku_id = #{skuId} and t.stock > 0

Update eb_sku t set t.sale = t.sale +1 where t.sku_id = #{skuId} 

首先我们容易想到和并发相关的几个方案 : 锁同步

    同步更多指的是应用程序的层面,多个线程进来,只能一个一个的访问,java中指的是syncrinized关键字。锁也有2个层面,一个是java中谈到的对象锁,用于线程同步;另外一个层面是数据库的锁;如果是分布式的系统,显然只能利用数据库端的锁来实现。

 

之后的asp.net的处理流程, 作为程序员我们是无法干涉的. 直到启动HttpApplication管道后, 我们才可以通过Global.asax或IHttpModule来控制请求处理过程, 在应用程序管道中适合做整页或用户控件的缓存. 如: 缓存热门页面, 我们可以自动缓存整个网站中访问量超过一定数值(阀值)的页面, 其中为了减小IO操作, 将缓存的页面放在内容中.

如果用户一直向购物车添加商品怎么办?并且他添加一次你查询一次数据库?互联网上用户那么多,这样会对数据库造成很大压力你怎么办?

在回答这个问题前,请想好自己的项目是否真的需要使用购物车?(SKU数少,商品结构单一等就不需要使用购物车了)

购物车的设计方案:

购物车的实现不存在哪种方式更好,完全是根据公司和项目架构相关的,类似苏宁使用的是数据库存储,但是国美使用的就是Session,不同的软件架构和不同的业务需求对应的购物车存储也是不一样的

用数据库存你得给数据库造成多大的负担啊, 而且对于购物车, 这种需要实时操作的东西, 数据库的访问量一大了, 就容易出现并发错误, 或者直接崩溃.

用Session确实效率很高, 而且会话是针对各个连接的, 所以便于管理, 但是用Session也不是完美的, 因为Session是有有效期的, 根据服务器的设置不同而不一样长, 如果你在购物的过程中Session超时了, 那么购物车中的东西就会全没了.不知道你看过当当网的购物车没有, 当你下线之后, 再次上线, 购物车中的东西还是存在的, 这对于用户来说非常方便.所以如果你的服务器够强的话, 你完全可以用一个静态变量来保存所有用户的购物车, 比如用一个静态的Map, 以IP作为Key,区分不同用户的购物车, 这样就可以使用户在下线的情况下也可以保存购物车中的内容.这种方法实现过, 只是没有用大量的并发访问测试其稳定性, 但是一定是可行的。 

采用存储过程将购物车存储于数据库相应表的方式,优点:数据稳定,不易丢失。缺点:效率低,增加数据库服务器负担。变量 + Datatable保存于客户端,优点:效率高,减轻数据库服务器负担。缺点:Session保存的变量容易丢失,但是一般情况下不会造成影响。变量 + 购物车对象保存于客户端,这种方式以面向对象为指导思想,逻辑上具有一定的复杂性。优点:效率高,减轻数据库服务器负担,使用便捷。缺点:Session保存的变量容易丢失,但是一般情况下不会造成影响

购物车的核心功能

 

购物车数据存数据库好处有很多,可以分析购买行为,可以为客户保存购买信息(不会因为浏览器关闭而丢失)等,我的这个项目的购物车使用的就是将购物车数据存数据库中,未登录时可以加20个商品,登录后可以加50个。

做促销时,商品详情页面的静态页面如何处理价格问题。

京东商品详情页虽然仅是单个页面,但是其数据聚合源是非常多的,除了一些实时性要求比较高的如价格、库存、服务支持等通过AJAX异步加载加载之外,其他的数据都是在后端做数据聚合然后拼装网页模板的。整个京东有数亿商品,如果每次动态获取如上内容进行模板拼装,数据来源之多足以造成性能无法满足要求;最初的解决方案是生成静态页,但是静态页的最大的问题:

1、无法迅速响应页面需求变更;

2、很难做多版本线上对比测试。如上两个因素足以制约商品页的多样化发展,因此静态化技术不是很好的方案。

 

数据主要分为四种:商品页基本信息、商品介绍(异步加载)、其他信息(分类、品牌、店铺等)、其他需要实时展示的数据(价格、库存等)。而其他信息如分类、品牌、店铺是非常少的,完全可以放到一个占用内存很小的Redis中存储;而商品基本信息我们可以借鉴静态化技术将数据做聚合存储,这样的好处是数据是原子的,而模板是随时可变的,吸收了静态页聚合的优点,弥补了静态页的多版本缺点;另外一个非常严重的问题就是严重依赖这些相关系统,如果它们挂了或响应慢则商品页就挂了或响应慢;商品介绍我们也通过AJAX技术惰性加载(因为是第二屏,只有当用户滚动鼠标到该屏时才显示);而实时展示数据通过AJAX技术做异步加载

 

1、接收商品变更消息,做商品基本信息的聚合,即从多个数据源获取商品相关信息如图片列表、颜色尺码、规格参数、扩展属性等等,聚合为一个大的JSON数据做成数据闭环,以key-value存储;因为是闭环,即使依赖的系统挂了我们商品页还是能继续服务的,对商品页不会造成任何影响;

2、接收商品介绍变更消息,存储商品介绍信息;

3、介绍其他信息变更消息,存储其他信息

 

技术选型

MQ可以使用如Apache ActiveMQ;

Worker/动态服务可以通过如Java技术实现;

RPC可以选择如alibaba Dubbo;

KV持久化存储可以选择SSDB(如果使用SSD盘则可以选择SSDB+RocksDB引擎)或者ARDB(LMDB引擎版);

缓存使用Redis;

SSDB/Redis分片使用如Twemproxy,这样不管使用Java还是Nginx+Lua,它们都不关心分片逻辑;

前端模板拼装使用Nginx+Lua;

数据集群数据存储的机器可以采用RAID技术或者主从模式防止单点故障;

因为数据变更不频繁,可以考虑SSD替代机械硬盘。

 

核心流程

1、首先我们监听商品数据变更消息;

2、接收到消息后,数据聚合Worker通过RPC调用相关系统获取所有要展示的数据,此处获取数据的来源可能非常多而且响应速度完全受制于这些系统,可能耗时几百毫秒甚至上秒的时间;

3、将数据聚合为JSON串存储到相关数据集群;

4、前端Nginx通过Lua获取相关集群的数据进行展示;商品页需要获取基本信息+其他信息进行模板拼装,即拼装模板仅需要两次调用(另外因为其他信息数据量少且对一致性要求不高,因此我们完全可以缓存到Nginx本地全局内存,这样可以减少远程调用提高性能);当页面滚动到商品介绍页面时异步调用商品介绍服务获取数据;

5、如果从聚合的SSDB集群/Redis中获取不到相关数据;则回源到动态服务通过RPC调用相关系统获取所有要展示的数据返回(此处可以做限流处理,因为如果大量请求过来的话可能导致服务雪崩,需要采取保护措施),此处的逻辑和数据聚合Worker完全一样;然后发送MQ通知数据变更,这样下次访问时就可以从聚合的SSDB集群/Redis中获取数据了。

 

基本流程如上所述,主要分为Worker、动态服务、数据存储和前端展示;因为系统非常复杂,只介绍动态服务和前端展示、数据存储架构;Worker部分不做实现。

商品搜索框的搜索联想如何实现?比如输入“羽绒” ,然后输入框下会列出很多关于羽绒服的搜索条件 “羽绒服男正品折扣 ”等等。

 

一个电商项目,在tomcat里面部署要打几个war包?

 

你说你用了redis缓存,你redis存的是什么格式的数据,是怎么存的?

购物车知识补充(在设计购物车时需要注意哪些细节)

为什么购物车的设计很重要?

①购物车是消费的最后一环

购物车在用户整体消费过程中一般是在最后一环,用户完整的消费体验应该是:打开APP或网站->浏览商品->加入购物车->确认订单并支付,在这个过程中,购物车和支付环节可以合并成一环,基本上用户点开购物车并开始填写地址的时候,就有很大的几率要完成购买,做好商品展现以及推送的环节,如果在最后的购物一环没有好的用户体验,岂不呜呼哀哉。

②购物车隐含的对比收藏功能

与现实购物车不同的是,网络消费者也比较喜欢把看中但不计划买的商品先放入购物车,或者把商品统一放到购物车直接进行比较,以备日后购买,因此从购物车保存的信息,就能够知道用户的大致偏好。

③购物车的重交易属性

用户在浏览商品涉及的只是前端展示,但购物车这一环涉及到最终的交易,对于用户来说,需要了解本次交易的基本物品信息、价格信息;而对于商户来说,确认收款、订单生成、物流环节都需要在这里获取到信息,才能完成本次的交易。

购物车设计需要展示的基本信息

购物车主要作用就是告诉用户买了什么,价格多少,不同类型的物品可能会有不同展示方式,但最基本的包括商品名称、价格、数量(若是服务,可能是次数)、其他附属信息。

 

哪些细节要让用户买得舒服?

亲,记得前面说的用户是如何看待购物车的功能吗?还记得你的用户会多次使用购物车,如果你只是完整做好信息展示不做好其他事情真的好吗?

①登录环节不要放在加入购物车前

请让用户先加入购物车,并在进行结算的时候在提醒用户需要登录。为什么?过早提醒用户需要登录才能购买,会打断用户浏览的流程(用户可能还要购买其他物品好吗?)这样的设置会让部分用户避而远之。

这里涉及到的一个点是在APP端需要记忆用户加入购物车的信息,与登录后的购物车信息合并(如果一开始没有这样考虑好,技术那可能会有难度)

②自动勾选用户本次挑选的商品

用户使用购物车有一个大的作用就是收藏,所以你要知道很多用户在购物车中积累了很多物品,当每次挑选加入购物车的商品,用户每次来到购物车要重新把本次的购买商品选上是很不好的体验。

所以这里一般是自动勾选本次挑选的商品,同样这里也要储存用户的勾选信息。

③陈列展示,注意沉底商品

让用户看见当前想买的商品就好了,把一些时间久远的,已经卖完的沉底显示。这样做的好处是能让用户看见之前的选择但没购买的商品,提醒一下说不定就又勾上买了哦!

④归类展示,可能增加购买

考虑如何进行归类展示,C2C可以按照商家分类,B2C可以按照品牌分类。

⑤价格和优惠的提醒

消费用户会关系自己每一次的消费价格,为避免商品列表过长隐藏价格信息,APP端一般会把总价固定底部提示。同时在合计信息中,展示优惠价格,能够促进消费者购买。

 

哪些细节要推动用户继续购买?

①还差一点就可以有优惠啦!

凑单,常用的手段包括运费见面或是满减促销,一般在网站底部会展示一些适合凑单的商品;在APP端可以给链接(不过需要权衡用户跳转会不会再跳回来哦!)

②提醒用户有些商品你真的可以买了

有关调查显示,加入购物车而没有购买的,在4小时以内提醒用户,会有27%的唤醒率哦!

所以需要提醒的几个点有:

生成订单但是还没支付的

商品有优惠信息

商品库存不足的

这些信息可以促进消费者购买,注意提醒的时间段,早上9点至晚上8点为宜,其他时间段就可能打扰用户咯(当然也要视产品类型而定啦,只不过大半夜提醒用户买东西确实不好,不是?)

 

购物车实现的三种方式

1. cookie

  cookie是由服务器产生,存储在客户端的一段信息。它定义了一种Web服务器在客户端存储和返回信息的机制,cookie文件它包含域、路径、生存期、和由服务器设置的变量值等内容。当用户以后访问同一个Web服务器时,浏览器会把cookie原样发送给服务器。通过让服务器读取原先保存到客户端的信息,网站能够为浏览者提供一系列的方便,例如在线交易过程中标识用户身份、安全要求不高的场合避免用户重复输入名字和密码、门户网站的主页定制、有针对性地投放广告等等。利用cookie的特性,大大扩展了WEB应用程序的功能,不仅可以建立服务器与客户机的联系,因为cookie可以由服务器定制,因此还可以将购物信息生成cookie值存放在客户端,从而实现购物车的功能。用基于cookie的方式实现服务器与浏览器之间的会话或购物车,有以下特点:

 

cookie存储在客户端,且占用很少的资源,浏览器允许存放300个cookie,每个cookie的大小为4KB,足以满足购物车的要求,同时也减轻了服务器的负荷;

cookie为浏览器所内置,使用方便。即使用户不小心关闭了浏览器窗口,只要在cookie定义的有效期内,购物车中的信息也不会丢失;

cookie不是可执行文件,所以不会以任何方式执行,因此也不会带来病毒或攻击用户的系统;

基于cookie的购物车要求用户浏览器必须支持并设置为启用cookie,否则购物车则失效;

存在着关于cookie侵犯访问者隐私权的争论,因此有些用户会禁止本机的cookie功能。

 

2. Session

 

  session是实现购物车的另一种方法。session提供了可以保存和跟踪用户的状态信息的功能,使当前用户在session中定义的变量和对象能在页面之间共享,但是不能为应用中其他用户所访问,它与cookie最重大的区别是,session将用户在会话期间的私有信息存储在服务器端,提高了安全性。在服务器生成session后,客户端会生成一个sessionid识别号保存在客户端,以保持和服务器的同步。这个sessionid是只读的,如果客户端禁止cookie功能,session会通过在URL中附加参数,或隐含在表单中提交等其他方式在页面间传送。因此利用session实施对用户的管理则更为安全、有效。

 

同样,利用session也能实现购物车,这种方式的特点是:

 

session用新的机制保持与客户端的同步,不依赖于客户端设置;

与cookie相比,session是存储在服务器端的信息,因此显得更为安全,因此可将身份标示,购物等信息存储在session中;

session会占用服务器资源,加大服务器端的负载,尤其当并发用户很多时,会生成大量的session,影响服务器的性能;

因为session存储的信息更敏感,而且是以文件形式保存在服务器中,因此仍然存在着安全隐患。

 

3. 结合数据库的方式

 

这也是目前较普遍的模式,在这种方式中,数据库承担着存储购物信息的作用,session或cookie则用来跟踪用户。这种方式具有以下特点:

数据库与cookie分别负责记录数据和维持会话,能发挥各自的优势,使安全性和服务器性能都得到了提高;

每一个购物的行为,都要直接建立与数据库的连接,直至对表的操作完成后,连接才释放。当并发用户很多时,会影响数据库的性能,因此,这对数据库的性能提出了更高的要求;

使cookie维持会话有赖客户端的支持。

 

各种方式的选择:

 

虽然cookie可用来实现购物车,但必须获得浏览器的支持,再加上它是存储在客户端的信息,极易被获取,所以这也限制了它存储更多,更重要的信息。所以一般cookie只用来维持与服务器的会话,例如国内最大的当当网络书店就是用cookie保持与客户的联系,但是这种方式最大的缺点是如果客户端不支持 cookie就会使购物车失效。

 

  Session 能很好地与交易双方保持会话,可以忽视客户端的设置。在购物车技术中得到了广泛的应用。但session的文件属性使其仍然留有安全隐患。

 

结合数据库的方式虽然在一定程度上解决了上述的问题,但从上面的例子可以看出:在这种购物流程中涉及到对数据库表的频繁操作,尤其是用户每选购一次商品,都要与数据库进行连接,当用户很多的时候就加大了服务器与数据库的负荷.

 

有的公司采用的是数据库的方式

1、用户浏览系统,获取用户机器的MAC地址

2、如果用户购买物品,添加到数据库里面,同时插入机器的MAC地址,也是用户的ID标示

3、如果用户登录系统,用用户真实的ID,更新当前机器的MAC对应的记录。

4、如果结帐的话,更新用户的id,删除购物车里面的东西

5、用户没有登录,购物车记录根据MAC读取记录,如果登录系统根据用户的ID,读取记录

 

 

希望对大家能够有所帮助!

相关推荐

相关文章