Java实现订单超时未支付自动取消的8种方法总结

Java实现订单超时未支付自动取消的8种方法总结

定时轮询

  • 数据库定时轮询方式,实现思路比较简单。启动一个定时任务,每隔一定时间扫描订单表,查询到超时订单就取消。
  • 优点:实现简单。
  • 缺点:轮询时间间隔不好确定,占用服务器资源,影响数据库性能。

惰性取消

  • 当查询订单信息时,先判断该订单是否超时,如果超时就先取消。
  • 优点:实现简单。
  • 缺点:影响查询之外的业务(如:统计、库存),影响查询效率。

JDK延迟队列

  • JDK延时队列DelayQueue是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素。

  • 简单实现代码demo如下,实际生产过程中会有专门的线程负责消息的入队与消费。

  • import java.util.concurrent.Delayed;
    import java.util.concurrent.TimeUnit;public class OrderDelayed implements Delayed {/*** 延迟时间*/private final Long time;/*** 订单编号*/public String orderNo;public OrderDelayed(String orderNo, long time, TimeUnit unit) {this.orderNo = orderNo;this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);}@Overridepublic long getDelay(TimeUnit unit) {return time - System.currentTimeMillis();}@Overridepublic int compareTo(Delayed o) {OrderDelayed orderDelayed = (OrderDelayed) o;long diff = this.time - orderDelayed.time;if (diff <= 0) {return -1;} else {return 1;}}
    }
    
  • import java.util.concurrent.DelayQueue;
    import java.util.concurrent.TimeUnit;public class Test {public static void main(String[] args) {DelayQueue<OrderDelayed> delayQueue = new DelayQueue<>();delayQueue.put(new OrderDelayed("220101001", 8, TimeUnit.SECONDS));delayQueue.put(new OrderDelayed("220101002", 4, TimeUnit.SECONDS));System.out.println("订单延迟队列开始执行");while (true) {// 取队列头部元素是否过期OrderDelayed task = delayQueue.poll();if (task != null) {// 取消订单业务逻辑System.out.println("订单 ---> " + task.orderNo + " 已过期准备取消");}}}
    }
    
  • 优点:效率高,任务触发时间延迟低。

  • 缺点:异常恢复困难,集群扩展麻烦,内存占用。

时间轮

  • 时间轮算法类似于时钟,会按某一个方向按固定频率轮动。可以用Netty的HashedWheelTimer来实现时间轮方法。

  • <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.78.Final</version>
    </dependency>
    
  • import io.netty.util.HashedWheelTimer;
    import io.netty.util.Timeout;
    import io.netty.util.Timer;
    import io.netty.util.TimerTask;import java.util.concurrent.TimeUnit;public class Test {public static void main(String[] args) {// 初始化时间轮Timer timer = new HashedWheelTimer();// 定时任务TimerTask task1 = new TimerTask() {public void run(Timeout timeout) throws Exception {// 取消订单业务逻辑System.out.println("订单1已过期准备取消");}};// 注册此定时任务(延迟时间为5秒,也就是说5秒后订单过期)timer.newTimeout(task1, 5, TimeUnit.SECONDS);// 定时任务TimerTask task2 = new TimerTask() {public void run(Timeout timeout) throws Exception {// 取消订单业务逻辑System.out.println("订单2已过期准备取消");}};// 注册此定时任务(延迟时间为3秒,也就是说3秒后订单过期)timer.newTimeout(task2, 3, TimeUnit.SECONDS);}
    }
    
  • 优点:效率高,任务触发时间延迟更低。

  • 缺点:异常恢复困难,集群扩展麻烦,内存占用。

Redis过期回调

  • Redis的key过期回调事件,也能达到延迟队列的效果。

  • 在redis.conf加入一条配置:

  • notify-keyspace-events Ex
    
  • 监听配置

  • @Configuration
    public class RedisListenerConfig {@BeanRedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);return container;}
    }
    
  • Redis过期回调监听方法

  • @Component
    public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {super(listenerContainer);}@Overridepublic void onMessage(Message message, byte[] pattern) {// 过期key,可以设置成订单号String expiredKey = message.toString();// 取消订单业务逻辑System.out.println("订单 ---> " + expiredKey + " 已过期准备取消");}
    }
    
  • 优点:数据不易丢失,集群扩展方便。

  • 缺点:需要额外维护redis。

Redis有序集合

  • Redis的数据结构Zset,同样可以实现延迟队列的效果,主要利用它的score属性,redis通过score来为集合中的成员进行从小到大的排序。通过zadd命令向队列delayqueue 中添加元素,并设置score值表示元素过期的时间。

  • 消费端轮询队列delayqueue, 将元素排序后取最小时间与当前时间比对,如小于当前时间代表已经过期移除key。

  • public void pollOrderQueue() {while (true) {Set<Tuple> set = jedis.zrangeWithScores(delayqueue, 0, 0);String value = ((Tuple) set.toArray()[0]).getElement();int score = (int) ((Tuple) set.toArray()[0]).getScore();int nowSecond = System.currentTimeMillis() / 1000);if (nowSecond >= score) {jedis.zrem(delayqueue, value);System.out.println(sdf.format(new Date()) + " removed key:" + value);}if (jedis.zcard(delayqueue) <= 0) {System.out.println(sdf.format(new Date()) + " zset empty ");return;}Thread.sleep(1000);}
    }
    
  • 优点:数据不易丢失,集群扩展方便。\

  • 缺点:可能重复消费同一key。

任务调度

  • 使用任务调度中间件xxl-job、ScheduleX、Elastic-Job等来实现,设置一个调度时间cron,到达订单过期的调度时间时,触发任务执行取消订单业务逻辑。

  • 例如使用xxl-job实现,订单创建时提交一个过期任务到xxl-job服务器,下面时执行器方法:

  • import com.xxl.job.core.handler.annotation.XxlJob;
    import org.springframework.stereotype.Component;@Component
    public class JobHandler {@XxlJob("payExpireJobHandler")public void payExpireJobHandler(String executorParam) {// 取消订单业务逻辑System.out.println("订单 ---> " + executorParam + " 已过期准备取消");}
    }
    
  • 优点:时效性强,支持分布式。

  • 缺点:实现复杂,维护成本高。

消息队列

  • 使用RocketMQ、RabbitMQ、Kafka的延时消息,消息在发送到消息队列服务端后并不会立马投递,而是根据消息中的属性延迟固定时间后才投递给消费者。

  • RocketMQ发送延时消息的示例代码如下:

  • import com.aliyun.openservices.ons.api.Message;
    import com.aliyun.openservices.ons.api.ONSFactory;
    import com.aliyun.openservices.ons.api.Producer;
    import com.aliyun.openservices.ons.api.PropertyKeyConst;
    import com.aliyun.openservices.ons.api.SendResult;
    import java.util.Properties;public class Test {public static void main(String[] args) {Properties properties = new Properties();// AccessKey ID阿里云身份验证,在阿里云RAM控制台创建。properties.put(PropertyKeyConst.AccessKey, "XXX");// AccessKey Secret阿里云身份验证,在阿里云RAM控制台创建。properties.put(PropertyKeyConst.SecretKey, "XXX");// 设置TCP接入域名,进入消息队列RocketMQ版控制台实例详情页面的接入点区域查看。properties.put(PropertyKeyConst.NAMESRV_ADDR,"XXX");Producer producer = ONSFactory.createProducer(properties);// 在发送消息前,必须调用start方法来启动Producer,只需调用一次即可。producer.start();Message msg = new Message( // 您在消息队列RocketMQ版控制台创建的Topic。"Topic",// Message Tag,可理解为Gmail中的标签,对消息进行再归类,方便Consumer指定过滤条件在消息队列RocketMQ版服务器过滤。"tag",// Message Body可以是任何二进制形式的数据,消息队列RocketMQ版不做任何干预,需要Producer与Consumer协商好一致的序列化和反序列化方式。"Hello MQ".getBytes());// 设置代表消息的业务关键属性,请尽可能全局唯一。// 以方便您在无法正常收到消息情况下,可通过控制台查询消息并补发。// 注意:不设置也不会影响消息正常收发。msg.setKey("ORDERID_100");try {// 延时消息,在指定延迟时间(当前时间之后)进行投递。最大可设置延迟40天投递,单位毫秒(ms)。// 以下示例表示消息在3秒后投递。long delayTime = System.currentTimeMillis() + 3000;// 设置消息需要被投递的时间。msg.setStartDeliverTime(delayTime);SendResult sendResult = producer.send(msg);// 同步发送消息,只要不抛异常就是成功。if (sendResult != null) {System.out.println(new Date() + " Send mq message success. Topic is:" + msg.getTopic() + " msgId is: " + sendResult.getMessageId());}} catch (Exception e) {// 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理。System.out.println(new Date() + " Send mq message failed. Topic is:" + msg.getTopic());e.printStackTrace();}// 在应用退出前,销毁Producer对象。// 注意:如果不销毁也没有问题。producer.shutdown();}
    }           
    
  • RocketMQ延时消息的订阅与普通消息订阅一致。

  • 优点:高效,好扩展,支持分布式。

  • 缺点:实现复杂,维护成本高。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/229653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决spa页面首屏加载慢的方式笔记

1.减少入口文件的体积 路由懒加载&#xff1a;在需要的时候进行加载&#xff0c;按需加载 前提&#xff1a;进行懒加载的子模块需要是一个单独的文件&#xff0c;所以要实现懒加载&#xff0c;就得先将进行懒加载的子模块&#xff08;子组件&#xff09;分离出来 vue router 支…

微服务Redis-Session共享登录状态

一、背景 随着项目越来越大&#xff0c;需要将多个服务拆分成微服务&#xff0c;使代码看起来不要过于臃肿&#xff0c;庞大。微服务之间通常采取feign交互&#xff0c;为了保证不同微服务之间增加授权校验&#xff0c;需要增加Spring Security登录验证&#xff0c;为了多个服务…

关于MSSQL存储过程的功能和用法

MSSQL存储过程是一种在Microsoft SQL Server数据库中存储和执行SQL代码的数据库对象。它可以用于数据处理和计算、数据库管理、事务处理以及实现安全性等多种功能。 以下是MSSQL存储过程的主要功能和用法&#xff1a; 数据处理和计算&#xff1a;可以使用MSSQL存储过程进行数…

#投屏,数据传输,局域网,远程,视频分享方式

步骤&#xff1a; 打开蓝牙配对连接 手机与电脑&#xff1a; 手机主动连接不上。电脑却可以连接手机。 连接上了&#xff0c;手机却不能向电脑传输文件&#xff0c;电脑可以向手机传输文件。 手机不能发送文件&#xff0c;很奇怪。但是电脑却可以向手机发送文件。 而且新老…

常用网安渗透工具及命令(扫目录、解密爆破、漏洞信息搜索)

目录 dirsearch&#xff1a; dirmap&#xff1a; 输入目标 文件读取 ciphey&#xff08;很强的一个自动解密工具&#xff09;&#xff1a; john(破解密码)&#xff1a; whatweb指纹识别&#xff1a; searchsploit&#xff1a; 例1&#xff1a; 例2&#xff1a; 例3&…

Git----学习Git第一步基于 Windows 10 系统和 CentOS7 系统安装 Git

查看原文 文章目录 基于 Windows 10 系统安装 Git 客户端基于 CentOS7 系统安装部署 Git 基于 Windows 10 系统安装 Git 客户端 &#xff08;1&#xff09;打开 git官网 &#xff0c;点击【windows】 &#xff08;2&#xff09;根据自己的电脑选择安装&#xff0c;目前一般w…

【自顶向下看Java——深度剖析抽象类和接口】

系列文章目录 欢迎大家订阅《计算机底层原理》、《自顶向下看Java》专栏、能够帮助到大家就是对我最大的鼓励、我会持续为大家输出优质内容&#xff0c;敬请期待&#xff01; 系列文章目录 文章目录 前言 一、抽象类 什么是抽象类&#xff1f; 为什么要使用抽象类&#xff1f; …

@Data@NoArgsConstructor@AllArgsConstructor 这几个常用注解什么意思?

这三个注解通常用于简化Java类的开发&#xff0c;特别是在使用一些框架时&#xff0c;如Lombok。让我们逐个解释这些注解的作用&#xff1a; 1. Data Data 是 Lombok 提供的一个组合注解&#xff0c;它包含了一组常用注解的功能&#xff0c;如 ToString、EqualsAndHashCode、…

一种解决Qt5发布release文件引发的无法定位程序输入点错误的方法

目录 本地环境问题描述分析解决方案 本地环境 本文将不会解释如何利用Qt5编译生成release类型的可执行文件以及如何利用windeployqt生成可执行的依赖库&#xff0c;请自行百度。 环境值操作系统Windows 10 专业版&#xff08;22H2&#xff09;Qt版本Qt 5.15.2Qt Creator版本5.0…

K8S的一个pod中运行多个容器

通过deployment的方式部署 创建一个deployment文件 [rootk8s-master1 pods]# cat app.yaml apiVersion: apps/v1 kind: Deployment metadata:name: dsfnamespace: applabels:app: dsf spec:replicas: 1selector:matchLabels:app: dsftemplate:metadata:labels:app: dsfspec:i…

P2P如何使用register_attention_control为UNet的CrossAttention关联AttentionStore

上次的调试到这里了&#xff0c;写完这篇接着看&#xff0c;prepare_latents_ddim_inverted 如何预计算 inversion latents&#xff1a; /home/pgao/yue/FateZero/video_diffusion/pipelines/p2p_ddim_spatial_temporal.py 1. 原始的UNet3D的CrossAttention和SparseCausalAtte…

深度学习中的潜在空间

1 潜在空间定义 Latent Space 潜在空间&#xff1a;Latent &#xff0c;这个词的语义是“隐藏”的意思。“Latent Space 潜在空间”也可以理解为“隐藏的空间”。Latent Space 这一概念是十分重要的&#xff0c;它在“深度学习”领域中处于核心地位&#xff0c;即它是用来学习…

C#基础知识 - 操作数与运算符篇

C#基础知识 - 操作数与运算符篇 4.1 表达式 - 操作数与运算符组成4.1.2 C#中常见的表达式类型&#xff1a;4.1.2 表达式示例 更多C#基础知识详解请查看&#xff1a;C#基础知识 - 从入门到放弃 4.1 表达式 - 操作数与运算符组成 C#中&#xff0c;表达式&#xff08;expression…

kafka入门(四):kafka生产者发送消息

创建生产者实例和构建消息之后&#xff0c;就可以开始发送消息了。 发送消息主要有三种模式&#xff1a;发后即忘、同步、异步。 发后即忘&#xff1a; 就是直接调用 生产者的 send方法发送。 发后即完&#xff0c;只管往 kafka中发送消息&#xff0c;而不关心消息是否正确…

用GitBook制作自己的网页版电子书

用GitBook制作自己的网页版电子书 前言 几年前阅读过其他人用GitBook创建的文档&#xff0c;可以直接在浏览器中打开&#xff0c;页面干净整洁&#xff0c;非常清爽&#xff0c;至今印象深刻。 GitBook非常适合用来为个人或团队制作文档&#xff0c;对于我这种偶尔写博客的人…

和鲸科技CEO范向伟受邀出席港航数据要素流通与生态合作研讨会,谈数据资产入表的战略机会

近日&#xff0c;由上海虹口数字航运创新中心、龙船&#xff08;北京&#xff09;科技有限公司&#xff08;下简称“龙船科技”&#xff09;、华东江苏大数据交易中心联合举办的“港航数据要素流通与生态合作研讨会”圆满落幕&#xff0c;来自港航领域的近百名企业代表共同参与…

【Spark面试】Spark面试题答案

目录 1、spark的有几种部署模式&#xff0c;每种模式特点&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 2、Spark为什么比MapReduce块&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 3、简单说一下hadoop和spark的shuffle相同和差异&#xff1f;&#xff08;☆☆☆☆☆…

Spring Boot Docker Compose 支持中文文档

本文为官方文档直译版本。原文链接 Spring Boot Docker Compose 支持中文文档 引言服务连接自定义镜像跳过特定的容器使用特定Compose文件等待容器就绪控制 Docker Compose 的生命周期激活 Docker Compose 配置文件 引言 Docker Compose 是一种流行的技术&#xff0c;可用于为…

黑马头条--day02--2文章详情

一.上传之前的配置 1.上传js和css文件 在minio中创建leadnews桶&#xff0c; 在leadnews下面创建/plugins目录&#xff0c;在该目录下面分别创建js和css目录, 也就是/plugins/css和/plugins/js,向css中上传以下index.css: html {overflow-x: hidden; }#app {position: rel…

GPT实战系列-探究GPT等大模型的文本生成

GPT实战系列-探究GPT等LLM文本生成 GPT专栏文章&#xff1a; GPT实战系列-Baichuan2等大模型的计算精度与量化-CSDN博客 GPT实战系列-GPT训练的Pretraining&#xff0c;SFT&#xff0c;Reward Modeling&#xff0c;RLHF-CSDN博客 GPT实战系列-ChatGLM3本地部署CUDA111080Ti…