原文连接:http://www.studyshare.cn/blog-front/blog/details/1132/1spring
1、在各类电商网站下订单后会保留一个时间段,时间段内未支付则自动将订单状态设置为已过时。数据库
2、解决方案服务器
一、轮询数据库:实现一个定时器,每隔一段时间去检查一遍数据库里的全部订单,查看其状态是不是未支付而且已经到期。并修改这些数据的状态为已过时。框架
优势:方法简单,容易实现分布式
缺点:订单状态处理不及时,轮询数据库的次数中可能不少都并无修改订单(作的无用功),数据库频繁屡次被链接浪费数据库资源开销。网站
所以以上方式实际开发中基本不予采用。开发中真正实现限时订单采用如下两种方案:线程
二、Java自己的解决方案--DelayQueue,延时队列中间件
核心思想如图:blog
(1)、用户下单,保存订单到数据库的同时,将该订单以及订单的过时时间推入DelayQueue继承
(2)、启动一个检查订单到期的线程,该线程使用delayQueue的take()方法获取到期订单,该方法为阻塞方法,若是当前没有到期订单,该方法会一直阻塞等待,直到获取到订单后继续往下执行。
(3)、当take()获取到一个到期订单后,该线程按获取到的订单的id去数据库查询订单并去检查订单状态,若是为未支付,则将状态修改成已过时
2.一、SpringBoot框架下代码实现
延时队列实体Bean
延时订单业务处理接口
延时订单业务处理实现类
若是咱们只实现了以上的代码,会存在一个很严重的问题,由于延时订单是存在DelayQueue中的,而DelayQueue是存在内存中的,那么当系 统重启后,DelayQueue中的数据就被清空了,所以当系统从新启动的时候,须要在订单的实现类中去作一个检索数据库订单的操做,将已过时未支付的设置为已过时,将未过时未支付的从新推入DelayQueue队列中。代码以下:
@PostConstruct 注解不重复解释,上面代码中有注释
2.二、JFinal框架下代码实现
因为项目中接口工程使用的是JFinal框架,SpringBoot框架下实现限时订单很简单,而JFinal框架下实现有一点小麻烦,特别在此进行分享
(1)ItemVo类和SpringBoot下的如出一辙。再也不重复贴代码
(2)延时订单业务接口
(3)延时订单业务处理实现类
首先了解一下,在JFinal框架下会有一个初始化类JFinalConfig,继承该类能够作项目的一些初始化操做
该类有两个方法:
afterJFinalStart() :当JFinal框架初始化完成后执行,仅执行一次
beforeJFinalStop() :当JFinal框架关闭以前执行,仅执行一次
那么咱们的延时订单线程初始化与系统重启后检测数据库订单的操做就能够放到afterJFinalStart() 里面进行执行
系统关闭线程中断执行代码:
以上就完整实现了限时订单的功能。
三、ActiveMq消息中间件实现方案
使用DelayQueue方案适合在单台服务器上,若是在分布式环境下,DelayQueue方案则还须要进行改进,存在的问题就是多个服务器会抢夺同一个订单,解决方案就是分区处理,每一个服务器只负责本身的订单,无论其余服务器上的订单。
使用DelayQueue的方案在功能上比较好的实现了限时订单的功能,可是可扩展性和伸缩性并很差,那么接下来使用ActiveMq实现,既能实现功能,也能更好的扩展和伸缩(消息中间件的特性就是实现系统的解耦)
实现步骤:
一、用户下单保存到数据库的同时使用消息生产者发送一条消息到ActiveMq消息队列,注意:并非调用send就立刻发送,而是根据过时时间进行延迟发送。时间到期了才会发送这条消息到消息队列中。
二、当消息队列收到该消息的时候,将消息转发给订阅了该队列的消费者,消费者收到消息就去作订单状态检查
(1)、接口实现类
(2)、消息生产者--发送订单到期的消息到消息队列(按过时时间延迟发送)
(3)、消息消费者--修改订单过时状态
以上三个类就是使用ActiveMq消息中间件实现限时订单的全部代码。调用代码很简单就是保存订单的同时将消息发送到消息队列,不在赘述。