订单系统设计

一、订单系统介绍:

订单系统在电商系统中承载着非常重要的角色,在设计订单系统之前,必须先梳理订单系统上下游关系,只有划分清业务系统边界,才能确定订单系统的职责与功能,进而保证各系统之间高效简洁的工作。

由此可见,订单系统对上接收用户信息,将用户信息转化为产品订单,同时管理并跟踪订单信息和数据,承载了公司整个交易线的重要对客环节。对下则衔接产品系统、促销系统、仓储系统、会员系统、支付系统等,对整个电商平台起着承上启下的作用。

二、生成订单的流程:

订单本身内容并不复杂,只是需要在数据库中保存订单信息和订单商品明细,但是由于订单系统在整个电商系统中起着承上启下的作用,因此生成订单前后需要关联很多模块系统,比如仓储库存、会员系统、优惠券和赠品、配送系统等等模块,下图列举出了与订单系统关联的常见模块(当然不同的电商系统关联的模块肯定有不同):

从用户选择商品下单开始,生成一个订单的最基本简单的流程如下:

在生成订单之前会做安全性检查:包括库存检查,订单金额计算检查,优惠券和赠品检查等等,如果把这些检查写死在生成订单的流程中,以后需要扩充调整时就得修改生成订单的代码,那么这个地方可以应用责任链模式,抽象出拦截器链,当以后需要扩充时,只需要再单独增加一个拦截器的实现。

由于每个拦截器检查时,都需要将前端传的订单信息作为参数传入,因此这里需要定义一个OrderContext类,将前端传的订单信息放到OrderContext中。

拦截器的定义如下:

vbnet 复制代码
public Interface OrderInterceptor {
	Boolean check(OrderContext context);
}

三、售后的流程:

一个最简单的售后基本流程如下:

四、订单系统常见问题:

1、订单超时未支付则自动关闭订单如何实现:

a、定时任务查询并关闭超时未支付的订单;缺点很明显,时间不精准,有一定的延时性;

b、利用RabbitMQ死信队列机制来实现:当RabbitMQ中的一条正常的消息,因为过了存活时间(TTL过期),就会变成Dead Message,即死信。当一个消息变成死信之后,他就能被重新发送到死信队列中,基于这样的机制,就可以实现延迟消息了;

c、利用JDK的延迟队列DelayQueue来实现;

2、重复提交订单如何解决:

订单重复提交的原因无外乎两种:一是由于用户在短时间内多次点击下单按钮,或浏览器刷新按钮导致,二则是由于Nginx或类似于SpringCloud Gateway的网关层,进行超时重试造成的;

常见解决方案有如下几种:

a、前端在点击下单按钮后将按钮置灰;

b、后端提供一个接口用于生成全局唯一订单号,比如UUID或者NanoID,前端进入创建订单页面时先调用这个接口获取订单唯一ID,然后提交订单时再调用创建订单按钮时传入这个ID,如果是两次重复提交,则订单ID是相同的,那么后面那次的提交则可以丢弃;

c、与上面的方法基本相同,只是全局唯一订单ID是由前端生成的;

d、可以用 "用户ID + 分隔符 + 商品ID" 作为唯一标识,让持有相同标识的请求在短时间内不能重复下单。可以将这个唯一标识保存到redis中,并且设置在指定的秒数后自动删除,这样第二次重复的请求因为redis中存在这个唯一标识而认为是重复提交并丢弃。

3、库存扣减的时机:

a、第一种方案是在生成订单时检查库存是否充足,支付成功回调的时候扣减库存,退货时回滚库存。但是有可能出现用户在支付完成后的回调时扣减库存时发现库存不够的情况,解决办法是在支付之前再次检查下库存,如果库存不足则提示用户因为库存不足的原因不能支付订单。

b、第二种方案是在生成订单前检查库存是否充足,下单成功后扣减库存,如果用户超时未支付成功或者退货时回滚库存。这种方式就相当于在提交订单时临时锁住库存,直到超时未支付时就解锁库存,库存锁住的这段时间内,锁住的这个库存其他用户就不能再下单,很明显,锁住库存的时间也就是订单超时未支付的最大时间,这个时间不能太长,否则会导致库存被长期占用导致其他用户不能下单。

4、订单支付完成回调如何去重:

当用户支付订单后,微信或者支付宝通常会以异步的方式通知商家服务器,商家服务器需要返回success,如果不是,则微信或者支付宝则会不断重复通知商家服务器。既然这样,支付回调接口就需要进行幂等性处理。

这个问题很好解决,因为支付完成的回调数据里面包含订单号out_trade_no,同一笔订单的多次调用,这个订单号是相同的,因此可以用这个订单号来最幂等性处理。

5、用户已经支付,但是因为各种原因导致未收到支付回调而关闭的订单如何解决:

这种情况会导致订单因为没有收到支付回调,导致订单超时未支付而被关闭。解决办法有以下几种:

a、订单超时未支付时,通过微信或者支付宝的接口查询订单状态,如果是已经支付,则根据查询状态更新订单状态;

b、定时任务查询所有超时未支付的订单,去微信或支付宝查询订单状态,如果是已经支付,则根据查询状态更新订单状态;为优化效率,避免未支付的订单每次都去查询,每次查询完之后标识下这些订单是已经查询过的,这样定时任务下次查询时就不再去查询这些订单了;

c、增加手工处理订单状态的机制:当用户支付完后如果发现订单还是未支付状态,则用户联系客户,由客服确认后手工干预订单状态。

相关推荐
A尘埃几秒前
SpringBoot的数据访问
java·spring boot·后端
yang-23072 分钟前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
Marst Code7 分钟前
(Django)初步使用
后端·python·django
代码之光_198014 分钟前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端
编程老船长27 分钟前
第26章 Java操作Mongodb实现数据持久化
数据库·后端·mongodb
IT果果日记1 小时前
DataX+Crontab实现多任务顺序定时同步
后端
姜学迁2 小时前
Rust-枚举
开发语言·后端·rust
爱学习的小健3 小时前
MQTT--Java整合EMQX
后端
北极小狐3 小时前
Java vs JavaScript:类型系统的艺术 - 从 Object 到 any,从静态到动态
后端
tangdou3690986553 小时前
两种方案手把手教你多种服务器使用tinyproxy搭建http代理
运维·后端·自动化运维