商城项目

我要开发同款
proginn07181979132023年07月26日
148阅读

作品详情

概述
前端使用微信小程序实现,java 进行后台开发。以 springcloud 微服务为主要技术栈,主要实现商城销售商品主链路的开发(包含首页商品列表、商品分类-搜索、商品详情、购物车、订单、支付等从商品浏览到下单的完整链路)
以 pig4cloud 开源版开源框架为基础进行快速开发

主要技术栈
springboot springcloud(nacos、gateway、feign、hystrix、config等) mybatis mysql redis elasticsearch logstash nginx rabbitmq rocketmq spring-security seata zookeeper
nodejs vue

微服务模块
- pig4cloud 核心模块(nacos、admin、auth、gateway)
- 商品模块
- 搜索模块
- 订单模块
- 库存模块
- 支付模块

主要技术点
1. 商品模块
提供商品信息查询功能,有 spu、sku 等概念,spu 除了有基本的标题、价格、图片、分类等基本信息外,还有规格选择时的可视规格、默认选中 sku 等额外信息
spu 与 sku 为一对多关系,sku 还由 spec(规格)组成,关系也是一对多,sku 需要维护一组组的 spec 名称及其可选值,其中的关系较为复杂
商品模块需要处理这些关系,并处理好数据返回给前端

2. 搜索模块
使用 Elasticsearch 实现搜索能力,支持中文分词(ik)、拼音、自动补全提示功能。
支持过滤特定搜索条件(如分类、价格范围),支持特定需求排序(如价格升序)
数据基于 mysql 进行存储及更新,通过 logstash 定时任务 sql 读取数据库数据,过滤后输出到 es 中,保证数据实时更新

3. 订单模块(含购物车)
用户选定商品,及其 sku 后,可选择数量并将商品加入到购物车,前端将购物车使用 storage 进行存储
购物车会在一定条件下与后端数据进行同步及校验,后端提供了同步及校验接口
后端将购物车数据存储在 redis 中,前端请求校验时,会对购物车每一项的 sku 进行如商品状态(是否上架、可购买)、库存是否充足(限购)、
价格(是否发生变更等)
上述操作会向商品模块及库存模块请求数据,使用 feign 进行远程调用
完成购物车校验后,用户即可进行下单,订单创建页面用户需填写收货信息并对商品进行确认、选择支付方式(微信),
点击支付后,后端会先尝试验证并创建订单、校验商品状态、价格、库存(后面介绍),创建订单后返回前端
前端根据订单信息访问后端拉起预支付接口,向三方支付平台发起预支付请求,返回表单信息,并在小程序中拉起支付页面(微信)
用户完成支付后,三方服务器会访问后端预留的异步通知接口,后端验签、校对金额、更改订单状态、扣减库存、完成支付等,订单即完成

4. 库存模块(关于库存验证、锁定和扣减)
本系统设计订单支付有一个指定的时间范围(如 15 分钟),用户创建订单后到完成支付系统获得三方异步通知前,是有一定的时间差的,
在这个时间差内,用户已经预定的商品其他人将不可购买(避免超卖),但用户不一定会完成支付,所以不能直接到数据库中扣减库存。
本系统采用了库存锁定(预留)机制,用户下单后,系统会锁定一部分库存(使用 {oid}::{skuId}::{buyCount} 作为 redisKey 并设置一个 timeout),
在进行库存计算时,会将这些锁定库存计算再内,若用户完成支付,则删除这些锁定库存,并再数据库扣减库存,若用户超时未完成支付,
则 redis key 过期自动删除这些锁定库存
关于库存扣减加锁,库存扣减可以通过 skuId 使用数据库主键索引在写时加上数据库行锁,并使用 where 条件判断 库存 >= 购买数量,成立即成功扣减,
但考虑到数据库性能瓶颈,在 java 代码中需要进行一次预先判断,java 层面的锁我使用了 zookeeper curator 客户端实现分布式锁,
锁 key 使用 skuId 避免并发操作同一 sku,锁范围内查询库存并验证
使用 reids 扣减库存提高并发量
为了提高并发量,经过一系列验证进行数据库库存扣减前,使用 redis 进行扣减操作,而不直接使用数据库,此处需要借助 lua 脚本完成,在 lua 脚本中,
从 redis 获取当前库存量,计算购买数量并扣减库存,由于 redis 是单工作线程且 lua 脚本执行不会被打断,所以不需要额外加锁,
redis 基于内存具有更高效的处理能力。在扣减成功后,使用 rabbitmq 发送异步通知,数据库根据消息再进行库存扣减,根据当前压力进行调整。
此方案在高并发的同时,也有缺点,就是 redis 在极端情况下可能会丢失数据,可以采用集群或其他同步备份方案优化

5. 支付模块
由于使用了微信小程序,所以以微信支付为主
支付流程也比较简单
- 提交订单信息拉起预支付
- 根据返回预支付表单给前端拉起支付界面
- 支付完成后,微信服务器异步通知后端预留的接口
- 后端验签、核对订单信息(价格等)、扣减库存、更改订单状态等
- 返回 success 给微信服务器

6. 其他技术点
分布式事务问题
微服务间调用就必须考虑分布式事务的问题,如本系统支付成功后,更改订单状态和扣减库存,都需要远程调用其他服务,我使用了三种不同的方式实现
- seata
最简单的实现方式,加上 @GlobalTransational 即可,特点是同步,强一致性,性能较慢
- rocketmq 原生事务消息
先给 broker 发送半消息,本地事务执行成功后,再发送后续消息,broker 确认后,投递消息到队列,消费者消费消息
保证本地事务一定成功,但不能保证消费成功,要考虑消费失败的处理(消息重发、补偿机制),消费者要避免重读消费消息
特点是异步,BASE 理论,最终一致性
- rabbitmq 自己维护本地消息表
在本地事务执行中,往数据表插入一条记录(消息打标,记录事务状态),本地事务记录需要与业务表操作保证强一致性,在一个事务中,
本地事务完成后,发送一条消息到 rabbitmq,消费者接收到消息后,根据消息进行处理,若处理成功,则改变本地消息表中的状(或达最大重试次数),
需要考虑失败补偿,或人工处理
特点是异步,BASE 理论,最终一致性
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论