我自横刀向天笑,去留肝胆两昆仑。这篇文章主要讲述生成订单30分钟未支付,则自动取消,该怎么实现?相关的知识,希望能为你提供帮助。
第一时间送达 大家好,我是燕子!
# 引言
在开发中,往往会遇到一些关于延时任务的需求。例如
- 生成订单30分钟未支付,则自动取消
- 生成订单60秒后,给用户发短信
对上述的任务,我们给一个专业的名字来形容,那就是延时任务。那么这里就会产生一个问题,这个延时任务和定时任务的区别究竟在哪里呢?一共有如下几点区别
- 定时任务有明确的触发时间,延时任务没有
- 定时任务有执行周期,而延时任务在某事件触发后一段时间内执行,没有执行周期
- 定时任务一般执行的是批处理操作是多个任务,而延时任务一般是单个任务
下面,我们以判断订单是否超时为例,进行方案分析
# 方案分析
(1)数据库轮询
思路
该方案通常是在小型项目中使用,即通过一个线程定时的去扫描数据库,通过订单时间来判断是否有超时的订单,然后进行update或delete等操作
实现
博主当年早期是用quartz来实现的(实习那会的事),简单介绍一下
maven项目引入一个依赖如下所示?
< dependency>
< groupId> org.quartz-scheduler< /groupId>
< artifactId> quartz< /artifactId>
< version> 2.2.2< /version>
< /dependency>
调用Demo类MyJob如下所示
package com.rjzheng.delay1;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job
public void execute(JobExecutionContext context)
throws JobExecutionException
System.out.println("要去数据库扫描啦。。。");
public static void main(String[] args) throws Exception
// 创建任务
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("job1", "group1").build();
// 创建触发器 每3秒钟执行一次
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger1", "group3")
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3).repeatForever())
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
// 将任务及其触发器放入调度器
scheduler.scheduleJob(jobDetail, trigger);
// 调度器开始调度任务
scheduler.start();
运行代码,可发现每隔3秒,输出如下
要去数据库扫描啦。。。
优缺点
优点:简单易行,支持集群操作
缺点:
(1)对服务器内存消耗大
(2)存在延迟,比如你每隔3分钟扫描一次,那最坏的延迟时间就是3分钟
(3)假设你的订单有几千万条,每隔几分钟这样扫描一次,数据库损耗极大
(2)JDK的延迟队列
思路
该方案是利用JDK自带的DelayQueue来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素,放入DelayQueue中的对象,是必须实现Delayed接口的。
DelayedQueue实现工作流程如下图所示
文章图片
其中Poll():获取并移除队列的超时元素,没有则返回空
take():获取并移除队列的超时元素,如果没有则wait当前线程,直到有元素满足超时条件,返回结果。
实现
定义一个类OrderDelay实现Delayed,代码如下
package com.rjzheng.delay2;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class OrderDelay implements Delayed
private String orderId;
private long timeout;
OrderDelay(String orderId, long timeout)
this.orderId = orderId;
this.timeout = timeout + System.nanoTime();
public int compareTo(Delayed other)
if (other == this)
return 0;
OrderDelay t = (OrderDelay) other;
long d = (getDelay(TimeUnit.NANOSECONDS) - t
.getDelay(TimeUnit.NANOSECONDS));
return (d == 0) ? 0 : ((d < 0) ? -1 : 1);
// 返回距离你自定义的超时时间还有多少
public long getDelay(TimeUnit unit)
return unit.convert(timeout - System.nanoTime(),TimeUnit.NANOSECONDS);
void print()
System.out.println(orderId+"编号的订单要删除啦。。。。");
运行的测试Demo为,我们设定延迟时间为3秒
【生成订单30分钟未支付,则自动取消,该怎么实现()】
package com.rjzheng.delay2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
public class DelayQueueDemo
public static void main(String[] args)
// TODO Auto-generated method stub
List< String> list = new ArrayList< String> ();
list.add("00000001");
list.add("00000002");
list.add("00000003");
list.add("00000004");
list.add("00000005");
DelayQueue< OrderDelay> queue = newDelayQueue< OrderDelay> ();
long start = System.currentTimeMillis();
for(int i = 0; i< 5; i++)
//延迟三秒取出
queue.put(new OrderDelay(list.get(i),
TimeUnit.NANOSECONDS.convert(3,TimeUnit.SECONDS)));
try
queue.take().print();
System.out.println("After " +
(System.currentTimeMillis()-start) + " MilliSeconds");
catch (InterruptedException推荐阅读
- 《持续集成实践指南》第2章 持续集成环境搭建Jenkins+Gitlab+Gerrit
- shell正则表达式(sedawk 之文本三剑客其二)
- 仪表板和管理面板中的WordPress自定义分类术语自定义顺序
- WordPress自定义分类术语描述html标签
- WordPress自定义查询分页
- wordpress自定义帖子类型按标签ID循环
- WordPress连接字符串
- WordPress-为特定菜单定制的wp_nav_menu
- 找不到WordPress自定义字体