如果乘客下单之后,X信出现了闪退,然后过了半个小时,乘客重新登录小程序,因为数据库中存在没有接单的订单,小程序会跳转到create_order.vue页面,继续开始倒计时等待司机接单。由于抢单缓存早就销毁了,即使倒计时结束,发起AJAX请求关闭订单。但是业务层发现没有抢单缓存,那么可能就有司机接单了(实际上根本没有司机接单),又关闭不了订单。于是就僵持在这里了。
为了避免上面情况的发生,我们要用JAVA程序监听抢单缓存的销毁事件,赶紧把关联的订单和账单记录给删除掉。即使像上面那样,乘客半小时后登录小程序,因为没有订单了,所以乘客可以重新下单。
如何监听redis中订单缓存销毁事件:
订单子系统的config文件夹内
@Configuration
public class RedisConfiguration {
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Bean
public ChannelTopic expiredTopic() {
/*
* 自定义Redis队列的名字,如果有缓存销毁,就自动往这个队列中发消息
* 每个子系统有各自的Redis逻辑库,订单子系统不会监听到其他子系统缓存数据销毁
*/
return new ChannelTopic("__keyevent@5__:expired");
}
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
return redisMessageListenerContainer;
}
}
redis中自带消息队列功能,这个消息队列专门接受销毁过期消息事件的。
订单子系统的config文件夹内
@Slf4j
@Component
public class KeyExpiredListener extends KeyExpirationEventMessageListener {
@Resource
private OrderDao orderDao;
@Resource
private OrderBillDao orderBillDao;
public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
@Transactional
public void onMessage(Message message, byte[] pattern) {
//从消息队列中接收消息
if (new String(message.getChannel()).equals("__keyevent@5__:expired")) {
//反序列化Key,否则出现乱码
JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
String key = serializer.deserialize(message.getBody()).toString();
if (key.contains("order#")) {
long orderId = Long.parseLong(key.split("#")[1]);
HashMap param = new HashMap() {{
put("orderId", orderId);
}};
int rows = orderDao.deleteUnAcceptOrder(param);
if (rows == 1) {
log.info("删除了无人接单的订单:" + orderId);
}
rows = orderBillDao.deleteUnAcceptOrderBill(orderId);
if (rows == 1) {
log.info("删除了无人接单的账单:" + orderId);
}
}
}
super.onMessage(message, pattern);
}
}