完整版订单超时自动取消功能
前几天对实习还是继续学习技术产生了抉择,问了一个前辈,他抛给我一个问题,怎么做15分钟订单自动取消,我说然后到时间之后,自动执行这个订单关闭业务,比如把锁了的库存给解开等等操作,然后在数据库里肯定要有体现,比如抖音,查我的订单内一块,在前段应该显示已过期,把支付的按钮变灰或者取消,支付的时候不能直接对库存进行操作,应该是支付模块调用订单模块调用库存模块。
然后把理论予以实现,发现需要考虑的点还是有一些的。
功能架构
该功能使用了三大模块解除耦合,保证高可用性,从高层到底层分别是支付模块->订单模块->商品模块,各司其职,支付模块主要负责支付,退款等相应功能;订单模块主要负责订单查询,订单创建,删除订单相关功能;商品模块主要负责商品上下架,补货,查货相关功能;是环环相扣的,支付模块通过操控订单实现支付,订单模块通过操控商品来实现订单创建等操作。
功能实现流程
由于是全栈开发,本功能实现流程会涵盖前后端都有。由于管理模块,就是添加商品等等操作,在前端并没有实现,就先在数据库里加一些商品。sql如下:

然后写一个接口获取商品列表,然后前端进行渲染,效果如下:

测试阶段,未接入微信支付等,但有字段标识,后期方便扩展,渲染的时候只需要有一点,判断支付类型,如果是钱支付就渲染成¥的形式,如果是积分就渲染成积分的形式。然后点击兑换会弹出一个弹出框如下:

扩展一些信息也会变得非常简单,由于数据库里设置了两个字段一个是销售价(也就是优惠后的价格),一个是原价,直接在前端算出优惠金额即可。然后点击提交订单,就会向后端去发送一个创建的请求,java代码如下所示:
// 这里先把订单持续事件设置成15秒// 1.1 先校验参数,看看该商品是否有库存CommonGoodPo good = goodMapper.queryGoodById(dto.getGoodId());if (good == null) return Result.error("已查询不到该商品");Boolean isPut = good.getIsPut();if (!isPut) return Result.error("无法对已下架的商品下订单");// 1.2 看看库存还够不够Boolean haveStore = good.getHaveStore();Integer store = good.getStore();if (haveStore && store <= 0) return Result.error("库存不足,无法下单");// 库存足就锁定一个库存if (haveStore) goodMapper.lockStore(good.getId());// 1.3 todo 如果有一个人只能买一单等等限制,可继续扩展// 2.1 然后就要生成订单的信息了,比如订单的id,这里起始应该使用杂乱的数字字母等作为id,图方便就直接使用自增id// 2.2 然后生成开始时间和结束时间LocalDateTime now = LocalDateTime.now();LocalDateTime end = LocalDateTime.now().plusMinutes(15); // 15分钟写死PopOrderVo popOrderVo = new PopOrderVo(null, good.getId(), now, end, 15 * 60, dto.getAccount());orderMapper.creatOrder(popOrderVo);// 3 准备对象,发送消息String mes = JSON.toJSONString(popOrderVo);sendDelayMessage(mes, 60 * 15, RabbitConstants.DELAY_ORDER_DEL_DIRECT_EXCHANGE, RabbitConstants.DELAY_ORDER_KEY);// 然后封装一下给前端,然后前端得到信息后,弹出弹出层,在我的订单里也可以找到该信息return Result.ok(popOrderVo);
代码逻辑主要分为三部分,校验参数;然后去执行sql,就是向数据库的order表里去添加一条订单消息,并且要锁库存;最后向rabbitMQ里发一条延迟消息,这个是封装好的方法。到期执行的方法如下所示:
log.error("我要开始喽!");// 把msg转成对象PopOrderVo popOrderVo = null;try {popOrderVo = JSON.parseObject(msg, PopOrderVo.class);} catch (Exception e) {throw new RuntimeException("请调用符合规定的api,类型转换错误,无法转换为PopOrderVo");}// 自动取消订单逻辑LocalDateTime now = LocalDateTime.now();Integer orderId = popOrderVo.getOrderId();Integer goodId = popOrderVo.getGoodId();// 修改订单状态orderMapper.finishOrder(orderId, now, ORDER_STATUS_OVERTIME);// 把锁了的库存释放goodMapper.unLockStore(goodId);log.error("我结束喽!");
就是去校验一下参数,然后去解锁库存,然后修改订单状态。
订单表如下所示:

然后在点击提交订单后,弹出支付页面,并有前端实现的倒计时。

然后会显示一些订单信息,倒计时到了之后,按钮会变成灰色,并无法点击,点击支付按钮后,进入到后端逻辑。代码如下:
@Override@Transactionalpublic Result payOrder(PayOrderDto dto) {Integer orderId = dto.getOrderId();OrderPo orderInfo = orderMapper.getOrderInfo(orderId);Integer goodId = orderInfo.getGoodId();LocalDateTime now = LocalDateTime.now();CommonGoodPo good = goodMapper.queryGoodById(goodId);// 1 先需要校验参数// 1.1 看过没过期,如果现在的时间在截止时间之后,则证明过期了if (now.isAfter(orderInfo.getEndTime())) {return Result.error("该订单已经过期,请重新下单!");}// 1.2 看一下状态是不是待支付状态if (orderInfo.getStatus() != 0) return Result.error("该订单已被处理,请刷新重试");// 1.3 看余额够不够Boolean isEnough = payMapper.checkBalance(orderInfo.getAccount(), good.getSalePrice());// 2.1 如果不够,直接报错余额不足if (!isEnough) return Result.error("你的余额不足,无法完成支付");// 2.2 如果够,扣减余额payMapper.decreaseBalance(orderInfo.getAccount(), good.getSalePrice());// 2 需要进行三个方面的处理// 2.1 商品给增加销量等等goodMapper.increaseSales(goodId);// 2.2 设置订单状态,截至时间等orderMapper.finishOrder(orderId, now, ORDER_STATUS_SUCCESS);// 2.3 记录支付日志payMapper.logPay(good.getSalePrice(), good.getPayType(), orderInfo.getAccount(), now, goodId);
// return null;return Result.ok("支付成功");}
支付逻辑比较简单,就是校验参数,但需要注意需要检验一下订单状态,因为可能因为网络问题等等,导致请求到后端的时候,出现时间延迟问题,出现状态已经不是待支付状态已经被修改的问题(处理幂等问题),余额不足问题,这时就不能再进行支付,要对订单进行一下处理。如果满足条件就进行sql操作。
然后在前端为了订单的丢失,又写了一个我的订单页面,如下所示:

可以根据不同的状态去筛选不同的订单列表,然后并可以在此页面完成支付。
至此本功能结束,使用的是rabbitMQ的延迟队列实现定时操作,也可以使用xxl-job,直接使用策略模式扩展一下即可,在复习专栏里有关于设计模式的文章和例子,后续有时间会讲一下定时操作策略的扩展。
相关文章:
完整版订单超时自动取消功能
前几天对实习还是继续学习技术产生了抉择,问了一个前辈,他抛给我一个问题,怎么做15分钟订单自动取消,我说然后到时间之后,自动执行这个订单关闭业务,比如把锁了的库存给解开等等操作,然后在数据…...
算法刷题:300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组、1143. 最长公共子序列
300. 最长递增子序列 1.dp定义:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度 2.递推公式:if (nums[i] > nums[j]) dp[i] max(dp[i], dp[j] 1); 注意这里不是要dp[i] 与 dp[j] 1进行比较,而是我们要取dp[j] 1的最大值…...
go 笔记
数据结构与 方法(增删改查) 安装goland,注意版本是2024.1.1,不是2024.2.1,软件下载地址也在链接中提供了 ‘go’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 在 Windows 搜索栏中输入“环境变量”&#…...
路由等保测评
1.身份鉴别 应对登录的用户进行身份标识和鉴别, 身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换。 可以使用“ service password-encryption"命令对存储在配置文件中的所有口令和类似数据进行加密, 以避免攻击者通过读取配…...
C# 反射之动态生成dll/exe
这个可能应该属于反射的高级使用范围了,平常在项目中使用的人估计也不是很多。由于使用反射的话会降低性能,比如之前用到的GetValue、SetValue等之类,但是使用这种方式会大大提高效率,在这里我只想说,都直接写IL指令了…...
Rust 所有权 Slices
文章目录 发现宝藏1. Slice 的基础知识1.1 什么是 Slice?1.2 如何创建 Slice? 2. 处理字符串 Slice2.1 字符串的 Slice2.2 字符串的 Unicode 和切片 3. 在函数中使用 Slice3.1 传递 Slice 给函数3.2 可变 Slice 的函数 4. 复杂示例4.1 处理多维数组的 Sl…...
windows 安全与网络管理问题
问题:当编写的脚本或程序运行的时候,可能被windows阻止访问网络甚至被删除 避免被删除 wini 进入设置界面 -> 选择更新与安全 -> 选择windwos defender -> 点击添加排除项,将指定的文件或目录排除,避免被软件删除 允许…...
基于Python实现一个庆祝国庆节的小程序
功能: 添加互动功能:允许用户选择不同的祝福语或者查询不同的国庆节信息。动态背景音乐:播放国庆节相关的背景音乐。增加节日小测验:提供一些关于国庆节的趣味小测验,让用户参与。增强图形用户界面 (GUI):…...
Anaconda 安装与使用教程
Anaconda 安装与使用教程 介绍 Anaconda 是一个用于科学计算的 Python 和 R 的发行版,它包含了众多流行的科学计算、数据分析、机器学习等领域的库。本教程旨在帮助初学者快速上手 Anaconda,并学会如何使用其管理环境以及安装包。 第一步:…...
时序预测SARIMAX模型
1. 项目背景 本文基于kaggle平台相关竞赛项目,具体连接如下: Time Series Forecasting With SARIMAX 基本信息如内容说明、数据集、已提交代码、当前得分排名以及比赛规则等,如图【1】所示,可以认真阅读。 图 1 2. 数据读取 …...
gin集成jaeger中间件实现链路追踪
1. 背景 新业务线带来新项目启动,需要改进原有项目的基础框架和组件能力,以提升后续开发和维护效率。项目搭建主要包括技术选型、框架搭建、基础服务搭建等。这其中就涉及到链路追踪的内容,结合其中的踩坑情况,用一篇文章来说明完…...
前端层面----监控与埋点
前言: 站在产品的视角,经常会问如下几个问题: 产品有没有用户使用 用户用得怎么样 系统会不会经常出现异常 如何更好地满足用户需求服务用户 当站在技术视角时,经常会问如下几个问题: 系统出现异常的频率如何 异常…...
linux Command
linux Command 1. 系统监控命令 1.1 top top [param] top -H -p pid,查看进程pid下面的子线程。-b以处理模式操作-c显示完整的命令行而不只是显示命令名。-d 屏幕刷新间隔时间。-l 忽略失效过程。-s 保密模式。-S 累积模式。-u 【用户名】 指定用户名。-p 【进程…...
uniapp登录页面( 适配:pc、小程序、h5)
<!-- 简洁登录页面 --> <template><view class"login-bg"><image class"img-a" src"https://zhoukaiwen.com/img/loginImg/2.png"></image><image class"img-b" src"https://zhoukaiwen.com/im…...
关于OceanBase 多模一体化的浅析
在当今多元化的业务生态中,各行各业对数据库系统的需求各有侧重。举例来说,金融风控领域对数据库的高效事务处理(TP)和分析处理(AP)能力有着严格要求;游戏行业则更加注重文档数据库的灵活性和性…...
快速git
下载 sudo apt install git配置 $ git config --global user.name "John Doe" $ git config --global user.email johndoeexample.com没有空格可以不加双引号如果~/.ssh没有先创建(下一步用) ssh方式制作密钥 github解释 #以邮箱作为标签…...
欺诈文本分类检测(十四):GPTQ量化模型
1. 引言 量化的本质:通过将模型参数从高精度(例如32位)降低到低精度(例如8位),来缩小模型体积。 本文将采用一种训练后量化方法GPTQ,对前文已经训练并合并过的模型文件进行量化,通…...
2024.9.14(RC和RS)
一、replicationcontroller (RC) 1、更改镜像站 [rootk8s-master ~]# vim /etc/docker/daemon.json {"registry-mirrors": ["https://do.nark.eu.org","https://dc.j8.work","https://docker.m.daocloud.io",&…...
【算法随想录04】KMP 字符串匹配算法
这是字符串模式匹配经典算法。 给定一个文本 t 和一个字符串 s,我们尝试找到并展示 s 在 t 中的所有出现(occurrence)。 #include<bits/stdc.h>using namespace std;vector<int> KMP(string s) {int n s.size();vector<int&g…...
TCP和MQTT通信协议
协议分层 网络分层 协议应用层 Co AP MQTT HTTP传输层 UDP TCP网络层 IP链路层 Enternet 网络分层中最…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
表单设计器拖拽对象时添加属性
背景:因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...
