转载
自动取消失效订单(spring整合quartz)
2017年09月01日 14:16:38 menghuanzhiming 阅读数:4157
转载:http://www.cnblogs.com/qingxinshujuan/p/5403878.html
CronTrigger最详细的Cron表达式范例参考:http://blog.csdn.net/zixiao217/article/details/53075009
任务需求:
关闭超时未支付的订单,将订单信息置为失效状态
相关技术:
spring框架
quartz框架定时调度
实现思路:
1.在服务启动时,查询数据库中的已下单未支付的订单数据,按下单时间先后存入队列中,先下单的存到头不,后下单存入队列尾部,取队列的头元素
2.检测与现在的时间,如果超过40分钟,则执行数据操作,即关闭订单,但是只关闭未支付的订单,之后在将头元素从队列移出,并取出下一个元素进行检测,以此类推
3.如果检测出时间未到40分钟,则线程等待相应的时间差,之后在执行订单操作
相关问题:
1.在执行时要防止轮询任务追尾,即在上一个job未执行完毕时就开始下一次轮询,解决方法是在job上加@DisallowConcurrentExecution注解,该注解的作用是让下一次job要等待当前job执行完毕
2.设置的轮询间隔是35分钟一次,订单超时是40分钟,中间有5分钟的时间差,为了防止订单被多次加入队列中,在加入订单队列时要注意去重
相关代码
quartz任务的job,用于检测数据库失效订单并将其关闭,代码如下:
package com.taotao.order.scheduler;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import org.apache.log4j.Logger;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionException;
import com.taotao.order.pojo.Order;
/**
* quartz任务的job,用于检测数据库失效订单并将其关闭
* @DisallowConcurrentExecution 这个注解标明上个任务没有执行完毕不会执行下个任务
*/
@DisallowConcurrentExecution
public class CancelOrderJob1 {
//订单有效时间40分钟40 * 60 *
public static final long EFFTIVE_TIME = 1000;
private Logger logger = Logger.getLogger(CancelOrderJob1.class);
public void execute() throws JobExecutionException {
System.out.println("失效订单检测任务开始执行!");
Queue<Order> queue = new LinkedList<>();
// 在每次启动Job时去数据库查找失效订单,并加入到队列中(从数据库中查询,此处使用假数据)
List<Order> list = getInvalidOrder();
if (!list.isEmpty()) {
for (Order o : list) {
queue.offer(o);
}
}
// 获取队列的头元素,开始检测头订单是否失效
Order element = queue.peek();
while (element != null) {
//时间差值
Long diff = this.checkOrder(element);
if (diff != null && diff >= EFFTIVE_TIME) {
System.out.println("开始关闭订单" + element.getOrderId() + "下单时间" + element.getCreateTime());
// 弹出队列
queue.poll();
// 取下一个元素
element = queue.peek();
} else if (diff < EFFTIVE_TIME) {
try {
System.out.println("等待检测订单" + element.getOrderId() + "下单时间" + element.getCreateTime() + "已下单"
+ diff / 1000 + "秒");
//线程等待
Thread.sleep(EFFTIVE_TIME - diff);
} catch (InterruptedException e) {
e.printStackTrace();
logger.info("CancelOrderJob.checkOrder定时任务出现问题");
}
}
}
}
/**
* 获取订单的下单时间和现在的时间差
*
* @author wangpeiqing 2016年4月16日
* @param order
* @return
*
*/
public Long checkOrder(Order order) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Long diff = null;
if (order != null) {
Date createTime = order.getCreateTime();
try {
diff = sdf.parse(sdf.format(date)).getTime() - sdf.parse(sdf.format(createTime)).getTime();
} catch (ParseException e) {
e.printStackTrace();
}
}
// 返回值为毫秒
return diff;
}
/**
*
* @Title: getInvalidOrder
* @Description: TODO(生产订单假数据用于测试)
* @return List<Order> 返回类型
* @return
*/
private List<Order> getInvalidOrder() {
List<Order> invalidOrders = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Order order = new Order();
order.setOrderId(String.valueOf(i));
order.setCreateTime(new Date());
invalidOrders.add(order);
}
return invalidOrders;
}
}
spring整合quartz配置方式
spring的配置文件如下:
<!-- 配置取消订单job类 -->
<bean id="cancelOrderJob1" class="com.taotao.order.scheduler.CancelOrderJob1"/>
<!-- 配置取消订单JobDetail 使用MethodInvokingJobDetailFactoryBean这种方式job类不需要实现Job接口-->
<bean id="cancelOrderJobDetail1"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="cancelOrderJob1" />
</property>
<property name="targetMethod"> <!-- 要执行的方法名称 -->
<value>execute</value>
</property>
</bean>
<!-- 配置取消订单简单触发器trigger,启动项目立即执行 -->
<bean id="simpleTrigger1" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="cancelOrderJobDetail1"></property>
<property name="startDelay" value="500" />
<property name="repeatInterval" value="0" />
<property name="repeatCount" value="0" />
</bean>
<!-- 配置取消订单触发器trigger -->
<bean id="cancelOrderTrigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean ">
<property name="jobDetail" ref="cancelOrderJobDetail1"></property>
<property name="cronExpression" value="0 0/2 * * * ?"></property>
</bean>
<!-- 配置调度工厂 -->
<bean id="SpringJobSchedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<!-- 取消订单的两个触发器 -->
<ref bean="simpleTrigger1" />
<ref bean="cancelOrderTrigger1" />
</list>
</property>
</bean>
订单实体类:
package com.taotao.pojo;
import java.util.Date;
public class TbOrder {
private String orderId;
private String payment;
private Integer paymentType;
private String postFee;
private Integer status;
private Date createTime;
private Date updateTime;
private Date paymentTime;
private Date consignTime;
private Date endTime;
private Date closeTime;
private String shippingName;
private String shippingCode;
private Long userId;
private String buyerMessage;
private String buyerNick;
private Integer buyerRate;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId == null ? null : orderId.trim();
}
public String getPayment() {
return payment;
}
public void setPayment(String payment) {
this.payment = payment == null ? null : payment.trim();
}
public Integer getPaymentType() {
return paymentType;
}
public void setPaymentType(Integer paymentType) {
this.paymentType = paymentType;
}
public String getPostFee() {
return postFee;
}
public void setPostFee(String postFee) {
this.postFee = postFee == null ? null : postFee.trim();
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Date getPaymentTime() {
return paymentTime;
}
public void setPaymentTime(Date paymentTime) {
this.paymentTime = paymentTime;
}
public Date getConsignTime() {
return consignTime;
}
public void setConsignTime(Date consignTime) {
this.consignTime = consignTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Date getCloseTime() {
return closeTime;
}
public void setCloseTime(Date closeTime) {
this.closeTime = closeTime;
}
public String getShippingName() {
return shippingName;
}
public void setShippingName(String shippingName) {
this.shippingName = shippingName == null ? null : shippingName.trim();
}
public String getShippingCode() {
return shippingCode;
}
public void setShippingCode(String shippingCode) {
this.shippingCode = shippingCode == null ? null : shippingCode.trim();
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getBuyerMessage() {
return buyerMessage;
}
public void setBuyerMessage(String buyerMessage) {
this.buyerMessage = buyerMessage == null ? null : buyerMessage.trim();
}
public String getBuyerNick() {
return buyerNick;
}
public void setBuyerNick(String buyerNick) {
this.buyerNick = buyerNick == null ? null : buyerNick.trim();
}
public Integer getBuyerRate() {
return buyerRate;
}
public void setBuyerRate(Integer buyerRate) {
this.buyerRate = buyerRate;
}
}
package com.taotao.order.pojo;
import java.util.List;
import com.taotao.pojo.TbOrder;
import com.taotao.pojo.TbOrderItem;
import com.taotao.pojo.TbOrderShipping;
public class Order extends TbOrder{
private List<TbOrderItem> orderItems;
private TbOrderShipping orderShipping;
public List<TbOrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<TbOrderItem> orderItems) {
this.orderItems = orderItems;
}
public TbOrderShipping getOrderShipping() {
return orderShipping;
}
public void setOrderShipping(TbOrderShipping orderShipping) {
this.orderShipping = orderShipping;
}
}