1.pom.xml文件中引入jar包
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.16.4</version>
</dependency>
2.添加 RedissionClient的Bean对象
@Autowired
private RedissonClient redissonClient;
3.消息侦听器的使用
a.获取消息发布订阅监听对象rTopic
b.rTopic添加监听事件 String.class为消息类型 onMessage就是延迟处理的方法
c.获取对象持有者RBucket (桶的概念)
d.为桶设置订单编号(id),生存时间(5)和时间单位(TimeUnit.SECONDS 秒)
e.在订单结束后调用此方法 传入订单id
/**
* 新订单来了 设置订单自动取消
* @param id 订单id
*/
public void orderCancel(String id) {
RTopic rTopic = redissonClient.getTopic("__keyevent@" + 1 + "__:expired", new StringCodec());
rTopic.addListener(String.class, new MessageListener<String>() {
@Override
public void onMessage(CharSequence channel, String msg) {
OrderServeCombo orderServeCombo = orderServeComboService.getById(id);
if (ObjectUtils.isEmpty(orderServeCombo)) {
log.error("订单不存在,订单编号:{0}", id);
}
orderServeCombo.setStatus(OrderStatus.CANCEL);
orderServeComboService.saveOrUpdate(orderServeCombo);
}
});
RBucket bucket = redissonClient.getBucket("order");
bucket.set(id, 5, TimeUnit.SECONDS);
}
4.自动取消订单中,若服务器挂掉,上面方法不会执行
是对orderCancel的补充(产生原因:订单即将到期 服务器挂了 即将取消的订单 未做处理)
/**
* 处理未付款已过期 状态未取消的订单 是对orderCancel的补充(产生原因:订单即将到期 服务器挂了 即将取消的订单 未做处理)
*/
private synchronized void dealCancelOrder(){
Date now=new DateTime();
Date cancelDate = DateUtils.addMinutes(now, -1);
List<OrderServeCombo> list= orderServeComboService.list(Wrappers.<OrderServeCombo>lambdaQuery()
.eq(OrderServeCombo::getStatus,OrderStatus.OBLIGATION)
.le(OrderServeCombo::getCreateTime,cancelDate)
);
List<LambdaUpdateWrapper<OrderServeCombo>> wrapperList=new ArrayList<>();
list.forEach(e->{
e.setStatus(OrderStatus.CANCEL);
e.setTimeoutTime(DateUtils.addMinutes(e.getCreateTime(),1));
e.setUpdateTime(now);
});
orderServeComboService.updateBatchById(list);
}
5.所以要在服务器启动的时候,自动执行方法处理订单已经取消,状态未刷新的订单
@PostConstruct注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行(返回必须是void)。
执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
@PostConstruct
public void init() {
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(
1,
2,
5,
TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
/**
* 处理 取消订单
*/
dealCancelOrder();
}
});
}
6.也有可能服务器正常运行redis就是没执行订单过期的方法,如:(3.消息侦听器的使用)中未执行
所以在补充一条:每天一个时间点定时刷新 处理超时未付款订单
/**
* 每天1点 处理一下超时未付款订单
*/
@Scheduled(cron = "0 0 1 * * ?")
private void autoDealCancelOrder(){
dealCancelOrder();
}
最后完美解决。