如何实现生成订单30分钟内未支付则自动取消?

  • 数据库轮询
  • JDK的延迟队列
  • Quartz
  • 时间轮算法
  • 使用消息队列

数据库轮询

不是很推荐的一种方式,需要定时扫描数据库,借助定时任务工具,如果是多服务部署,那么还需要考虑分布式调度,推荐xxL-job。
缺点在于数据库压力大,而且会有延迟性。比如每隔3分钟进行扫描一次,最坏的情况就是那个取消支付要延迟3分钟行。

mysql定时器是系统给提供了event,下面创建表:
create table mytable (
id int auto_increment not null,
name varchar(100) not null default '',
introduce text not null,
createtime timestamp not null,
constraint pk_mytable primary key(id)
)创建存储过程,这里的存储过程主要提供给mysql的定时器event来调用去执行:
create procedure mypro()
BEGIN
insert into mytable (name,introduce,createtime) values ('1111','inner mongolia',now());
end;
这里只是简单的写了一下,只是为了说明例子。紧接着创建mysql的定时器event:
create event if not exists eventJob
on schedule every 1 second
on completion PRESERVE
do call mypro();
这里设置为每一秒执行一次至此所有的准备工作已经写完了,做完这些,mysql要想利用定时器必须的做准备工作,就是把mysql的定时器给开启了:
SET GLOBAL event_scheduler = 1;  -- 启动定时器
SET GLOBAL event_scheduler = 0;  -- 停止定时器紧接着还要开启事件:
ALTER EVENT eventJob ON  COMPLETION PRESERVE ENABLE;   -- 开启事件
ALTER EVENT eventJob ON  COMPLETION PRESERVE DISABLE;  -- 关闭事件SHOW VARIABLES LIKE '%sche%'; -- 查看定时器状态

https://www.cnblogs.com/mr-wuxiansheng/p/5962454.html

xxl-job中心式的调度平台轻量级,开箱即用,操作简易,上手快,与SpringBoot有非常好的集成,而且监控界面就集成在调度中心,界面又简洁,对于企业维护起来成本不高,还有失败的邮件告警等等。

xxl-job是通过一个中心式的调度平台,调度多个执行器执行任务,调度中心通过DB锁保证集群分布式调度的一致性,这样扩展执行器会增大DB的压力,但是如果实际上这里数据库只是负责任务的调度执行。但是如果没有大量的执行器的话和任务的情况,是不会造成数据库压力的。实际上大部分公司任务数,执行器并不多(虽然面试经常会问一些高并发的问题)。

JDK的延迟队列

利用JDK自带的无界阻塞队列DelayQueue来实现,该队列只有在延迟期满的时候才能从中获取元素,放入DelayQueue中的对象,是必须实现Delayed接口的。这种方式优点在于延时低,缺点就是一旦服务重启,之前放入队列的任务全部丢失。如果有大量的任务,可能会造成oom。代码复杂度也比较高。

package com.fchan.mq.jdkDelay;import com.fasterxml.jackson.annotation.JsonFormat;import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;public class MyDelay implements Delayed {/*** 延迟时间*/@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")private Long time;String name;public MyDelay(String name, Long time, TimeUnit unit) {this.name = name;this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);}public Long getTime() {return time;}public String getName() {return name;}//获取延时时间@Overridepublic long getDelay(TimeUnit unit) {return time - System.currentTimeMillis();}//对延时队列中的元素进行排序@Overridepublic int compareTo(Delayed o) {MyDelay myDelay = ((MyDelay) o);return this.time.compareTo(myDelay.getTime());}
}
package com.fchan.mq.jdkDelay;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;public class MyDelayDemo {public static void main(String[] args) throws InterruptedException {MyDelay myDelay1 = new MyDelay("MyDelay1", 5L, TimeUnit.SECONDS);MyDelay myDelay2 = new MyDelay("MyDelay2", 10L, TimeUnit.SECONDS);MyDelay myDelay3 = new MyDelay("MyDelay3", 15L, TimeUnit.SECONDS);DelayQueue<MyDelay> delayQueue = new DelayQueue<MyDelay> ();//add 和 put 后面都是调用的offer方法,内部使用了ReentrantLock//delayQueue.put();delayQueue.add(myDelay1);delayQueue.add(myDelay2);delayQueue.add(myDelay3);System.out.println("订单延迟队列开始时间:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));while (delayQueue.size() != 0) {/*** 取队列头部元素是否过期*///DelayQueue的put/add方法是线程安全的,因为put/add方法内部使用了ReentrantLock锁进行线程同步。// DelayQueue还提供了两种出队的方法 poll() 和 take() ,// poll() 为非阻塞获取,没有到期的元素直接返回null;// take() 阻塞方式获取,没有到期的元素线程将会等待。MyDelay task = delayQueue.poll();if (task != null) {System.out.format("任务:{%s}被取消, 取消时间:{%s}\n", task.name, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}Thread.sleep(1000);}}
}

Quartz

Quartz一款非常经典任务调度框架,在Redis、RabbitMQ还未广泛应用时,超时未支付取消订单功能都是由定时任务实现的。
Quartz缺点没有自带的管理界面;调度逻辑和执行任务耦合在一起;维护需要重启服务

时间轮算法

时间轮算法可以类比于时钟,如下图箭头(指针)按某一个方间按固定频率轮动,每一次跳动称为一个tick。这样可以看出定时轮由个3个重要的属性参数,ticksPerWheel(
轮的tick数),tickDuration(一个tick的持续时间)从及timeUnit(时间单位),例如当ticksPerWheel=60,tickDuration=1,timeUnit=秒,这就和现实中的始终的利针走动完全类似了。可从用Netty的HashedWheelTimer来进行使用,缺点和延识队列一样

使用消息队列

采用rabbitMQ的延时队列。RabbitMQ具有从下两个特性,RabbitMQ可以针对Queue和Message设置x-message-tt,来控制消息的生存时间,如果超时,则消息变为dead letter。
RabbitMQ的Queue可从配置x-dead-letter-exchange和x-
dead-letter-routing-key(可选)两个参数,用来控制队列内出现了deadletter,则按照这两个参数重新路由。结合以上两个特性,就可以模拟出延迟消息的功能。
优点就是高效,可以利用rabbitmq的分布式特性轻易的进行横句扩展,消息支持持久化增加了可靠性

public void send(String delayTimes) {amqpTemplate.convertAndSend("order.pay.exchange", "order.pay.queue","大家好我是延迟数据", message -> {// 设置延迟毫秒值message.getMessageProperties().setExpiration(String.valueOf(delayTimes));return message;});}
}

设置转发规则

/*** 延时队列*/@Bean(name = "order.delay.queue")public Queue getMessageQueue() {return QueueBuilder.durable(RabbitConstant.DEAD_LETTER_QUEUE)// 配置到期后转发的交换.withArgument("x-dead-letter-exchange", "order.close.exchange")// 配置到期后转发的路由键.withArgument("x-dead-letter-routing-key", "order.close.queue").build();}

除此之外 监听RedisKey过期时间进行定时任务并不可信
redis的过期监听并不可靠, 尤其是大量KEY的时候.很可能 会延迟推送.
redis官方链接

In order to obtain a correct behavior without sacrificing consistency, when a key expires, a DEL operation is synthesized in both the AOF file and gains all the attached replicas nodes. This way the expiration process is centralized in the master instance, and there is no chance of consistency errors.
However while the replicas connected to a master will not expire keys independently (but will wait for the DEL coming from the master), they’ll still take the full state of the expires existing in the dataset, so when a replica is elected to master it will be able to expire the keys independently, fully acting as a master.

大致意思是会生成del追加到aof中,副本没有自己的过期key,他会等待删除命令,
数据分析请勿过度依赖Redis的过期监听

如何实现生成订单30分钟内未支付则自动取消?相关推荐

  1. 面试官问:生成订单30分钟未支付,则自动取消,该怎么实现?

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源 | https://blog.csdn.net/hjm4702192/article/details/80519010 在开发 ...

  2. 面试官:生成订单30分钟未支付,则自动取消,该怎么实现?

    Hollis的新书限时折扣中,一本深入讲解Java基础的干货笔记! 目录 了解需求 方案 1:数据库轮询 方案 2:JDK 的延迟队列 方案 3:时间轮算法 方案 4:redis 缓存 方案 5:使用 ...

  3. 实现生成订单30分钟未支付,则自动取消

    目录 了解需求 方案 1:数据库轮询 思路 实现 优点 缺点 方案 2:JDK 的延迟队列 思路 实现 优点 缺点 方案 3:时间轮算法 思路 实现 优点 缺点 方案 4:redis 缓存 思路一 实 ...

  4. 生成订单30分钟未支付,则自动取消,该怎么实现?(典藏版)

    目录 方案分析 (1)数据库轮询 (2)JDK的延迟队列 (3)时间轮算法 (4)redis缓存 (5)使用消息队列 在开发中,往往会遇到一些关于延时任务的需求.例如 生成订单30分钟未支付,则自动取 ...

  5. Java 实现订单未支付超时自动取消

    在电商上购买商品后,如果在下单而又没有支付的情况下,一般提示30分钟完成支付,否则订单自动.比如在京东下单为完成支付: 超过24小时,就会自动取消订单,下面使用 Java 定时器实现超时取消订单功能. ...

  6. 订单30分钟未支付自动取消怎么实现?

    本文已经收录到Github仓库,该仓库包含计算机基础.Java核心知识点.多线程.JVM.常见框架.分布式.微服务.设计模式.架构等核心知识点,欢迎star~ 地址:https://github.co ...

  7. 订单30分钟未支付自动取消怎么实现

    了解需求 在开发中,往往会遇到一些关于延时任务的需求. 例如 生成订单 30 分钟未支付,则自动取消 生成订单 60 秒后,给用户发短信 对上述的任务,我们给一个专业的名字来形容,那就是延时任务.那么 ...

  8. Laravel 实现创建订单30分钟未支付自动关闭的功能

    文章目录 前情提要 什么是延迟分发 如何实现延迟分发 实现步骤(真实代码) 确保安装 redis 并且项目正常可用 将 .env 中队列配置项指定为 redis 在项目 app 目录下创建 Jobs ...

  9. java实现订单未支付失效_未支付订单30分钟后,自动取消

    未支付订单30分钟后,自动取消 生成订单时发起延时30分钟的任务 /** * 取消订单的任务 * @Title: startCancelOrderTask * @Description: 取消订单的任 ...

最新文章

  1. 富文本框让最大四百像素_TinyMCE 富文本编辑器 ━━ 基本配置
  2. 编译Android源码前的一个步骤
  3. 6、存储函数详解,创建,查看,修改,删除
  4. 区块链核心技术:拜占庭共识算法之PBFT全面理解
  5. Mybatis-sql语句的抽取
  6. java错误:The superclass javax.servlet.http.HttpServlet was not found on the Java Bu
  7. 给我的宏基上网本用U盘装XP系统
  8. 第二次裸辞_潜伏期_一些感想
  9. 黑龙江省国二c语言报名时间,2020年9月黑龙江省全国计算机等级考试报名通知
  10. ubuntu--雷鸟只能收邮件不能发邮件
  11. B00002 C语言位字段实例
  12. 安卓版微信自带浏览器和IE6浏览器ajax请求abort错误处理
  13. 白话大数据 | 从买菜这件小事来聊聊数据仓库
  14. 计算机卸载打不开,电脑卸载wps后excel打不开怎么办
  15. 扬帆际海—移动端流量对跨境电商有多重要?
  16. SaaS、PaaS、IaaS、DaaS、BaaS简介
  17. 抖音巨量服务商入驻流程
  18. java代码实现登录跳转_java实现登录案例
  19. 爱奇艺数据中台建设方案.ppt
  20. 易语言QQpost加好友源码

热门文章

  1. 【vue + Excel表格导入与导出】导入Excel并展示在el-table表格中,表格导出为Excel文件
  2. linux多串口改波特率,如何在S3C2440上linux操作系统下将串口的波特率提高以致921600...
  3. 计算机专业为什么学机床电焊,机械类最吃香的专业:为什么说学机械穷一辈子?...
  4. centOS7 下作网络桥接
  5. Java:物联网终端机如何生成唯一识别码
  6. 【Books系列】2021年:白岩松《白说》读书笔记
  7. android高级设置,开启安卓手机高级优化设置,流畅度瞬间提升6倍
  8. 共阴极的七段显示译码器的代码
  9. linux中 ~是什么意思。 cd ~ - ./ ../的区别
  10. 微信硬件蓝牙开发教程之添加蓝牙设备(1)