生成订单30分钟未支付,则自动取消,该怎么实现?

Posted 蜗牛201

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成订单30分钟未支付,则自动取消,该怎么实现?相关的知识,希望对你有一定的参考价值。

第一时间送达 大家好,我是燕子!


# 引言


在开发中,往往会遇到一些关于延时任务的需求。例如



  • 生成订单30分钟未支付,则自动取消
  • 生成订单60秒后,给用户发短信


对上述的任务,我们给一个专业的名字来形容,那就是延时任务。那么这里就会产生一个问题,这个延时任务和定时任务的区别究竟在哪里呢?一共有如下几点区别



  1. 定时任务有明确的触发时间,延时任务没有
  2. 定时任务有执行周期,而延时任务在某事件触发后一段时间内执行,没有执行周期
  3. 定时任务一般执行的是批处理操作是多个任务,而延时任务一般是单个任务


下面,我们以判断订单是否超时为例,进行方案分析


# 方案分析


(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实现工作流程如下图所示


生成订单30分钟未支付,则自动取消,该怎么实现?_java


其中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秒




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以上是关于生成订单30分钟未支付,则自动取消,该怎么实现?的主要内容,如果未能解决你的问题,请参考以下文章

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

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

生成订单30分钟未支付,则自动取消,该怎么实现?

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

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

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