大家肯定都有过在饿了么,或者在美团外卖下单的经历,下完单后,超过一定的时间,订单就被自动取消了。这就是延时任务。延时任务的应用场景相当广泛,不仅仅上面所说的饿了吗,美团外卖,还有12306,或者是淘宝,携程等等 都有这样的场景。这延时任务是怎么实现的呢?跟着我,继续看下去吧。
###1.在SQL查询,Serive层组装的时候做手脚
在拼接SQL或者Serive层做一些判断,比如 订单状态为 “已下单,但未支付”,同时 当前时间超过了 下单时间 15分钟,显示在用户端或者后台的订单状态就改为 “已取消”。
这种方式比较方便,也没有任何延迟,但是数据库里面的状态不是真实状态了。如果需要提供接口给其他部门调用的话,别忘了对这个订单状态做一些特殊处理。
###2.Job
这是最普通的方式之一了。就是开一个Job,每隔一段时间去循环订单,当满足条件后,修改订单状态。
这种方式也比较方便,但是会有一定的延迟,如果订单数据比较少的话,每分钟扫描一次,还是可以接受的,延迟也就在一分钟左右。但是订单数据一旦大了起来,可能一小时也扫描不完,那么延迟就相当恐怖了。而且不停的扫描数据库,对于数据库也是一种压力。
当然还可以做一些改进,比如扫描的时候加上时间范围,在一定时间以前的订单不扫描了,因为这些订单已经被上一次运行的Job给处理了。
第一种方式可以和第二种方式结合起来使用。
前面两个是比较常规的做法,如果数据量不大,使用起来,也不错。
###3.DelayQueue
DelayQueue是Java自带队列,从名字就可以知道它是一个延迟队列。
从上面的图可以知道DelayQueue是一个泛型队列,它接受的类型是继承Delayed的。也就是我们需要写一个类去继承(实现)Delayed。实现Delayed,需要重写两个方法:
public long getDelay(TimeUnit unit)
public int compareTo(Delayed o)
第一个方法:消息是否到期(是否可以被读取出来)判断的依据。当返回负数,说明消息已到期,此时消息就可以被读取出来了。
第二个方法:往DelayQueue里面塞入数据会执行这个方法,是数据应该排在哪个位置的判断依据。