写一个最简单的版本,因为我们是一个Schedule,不需要返回值,closeOrderTaskV1,第一个版本,那如果其实我们不是TOMCAT集群的话,我们这一个方法就OK了,但是我们是TOMCAT集群,所以呢,需要创建一个分布式锁,那第一个版本是没有分布式锁的,非常简单,我们一起来写一下,首先加上@Schedule这么一个注解,这个包是annotation里面的scheduled的,千万不要加错,然后括号里面写一下,我们需要它每一分钟执行一次,等于什么呢,用引号引一下,cron="0 */1 * * * ?",每个一分钟的整数倍,然后填充一下他的逻辑。
/**
* 没有分布式锁,运行起来来看日志。
*/
// @Scheduled(cron="0 */1 * * * ?")//每1分钟(每个1分钟的整数倍)
public void closeOrderTaskV1(){
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
iOrderService.closeOrder(hour);
}
从配置文件 = 里面获取这个配置,如果key不存在也是两个小时,那这里面的逻辑就是说,我们获取两个小时,也就是说每一分钟我都会执行一下,这个定时任务会关闭,以当前时间为准,两个小时之前下单,但是呢,未付款的订单,那为了验证方便呢,我们加一行日志,关闭订单定时任务启动,说明我们写的Spring Schedule定时任务,是生效的,因为我们的频率比较高,每一分钟要执行一次。
@Override
public void closeOrder(int hour) {
Date closeDateTime= DateUtils.addHours(new Date(),-hour);
List<Order> orderList = orderMapper.selectOrderStatusByCreateTime(
Const.OrderStatusEnum.NO_PAY.getCode(),
DateTimeUtil.dateToStr(closeDateTime));
for(Order order : orderList){
List<OrderItem> orderItemList = orderItemMapper.getByOrderNo(order.getOrderNo());
for(OrderItem orderItem : orderItemList){
//使用写独占锁,一定要用主键where条件,防止锁表。同时必须是支持MySQL的Innodb。
Integer stock = productMapper.selectStockByProductId(orderItem.getProductId());
//考虑到已生成的订单里的产品,被删除的情况
if(stock == null){
continue;
}
Product product = new Product();
product.setId(orderItem.getProductId());
product.setStock(stock+orderItem.getQuantity());
productMapper.updateByPrimaryKeySelective(product);
}
orderMapper.closeOrderCloseByOrderId(order.getId());
log.info("关闭订单OrderNo:{}",order.getOrderNo());
}
}
这个时候根据订单状态和createTime,开始找到orderList,那orderList我们一共找了755个,找到这订单的OrderItemList,根据productId拿他的库存,现在表里的库存是995个,这个 时候stock就是995加1,现在我们是单击来关闭没有问题,那如果我们再启动一个TOMCAT,现在我们要聚焦在分布式任务调度上,这样就造成了一个问题,什么问题,这个定时任务我只希望,在TOMCAT集群环境下,一个服务执行就可以了,并不需要大家都来执行它,并且如果大家一起执行的话,也浪费了MYSQL和服务器的一个性能,因为其他机器不需要执行,只执行一台就行,第二个就很容易造成数据错乱,因为大家都在执行SQL语句,那接下来我们就讲使用redis实现分布式锁的一个原理,来解决这一个问题。