订单超时取消的实现,首先想到的是定时任务,但是这种实现方式在订单量较大的情况下是有问题的,而且时间也会有误差,最大时间差就是定时任务的执行间隔时间。

使用redis的过期监听事件可以比较好的解决这个问题。实现的方式是订单创建后向redus中存一记录,一般就以订单号为key。设置过期时间(订单超时时间),一旦时间超时会触发监听事件,这时候就可以通过key判断这个订单是否支付,未支付时取消订单。

redis过期监听的实现:

1.修改redis.windows.conf配置文件中notify-keyspace-events的值

默认配置notify-keyspace-events的值为" ",修改为 notify-keyspace-events Ex 这样便开启了过期事件

基于Redis过期事件实现订单超时取消_spring

 

 2. 创建配置类RedisListenerConfig(配置RedisMessageListenerContainer这个Bean)



@Configuration
public class RedisListenerConfig {

@Autowired
private RedisTemplate redisTemplate;

/**
* 处理乱码
* @return
*/
@Bean
public RedisTemplate redisTemplateInit() {
// key序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
//val实例化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

return redisTemplate;
}


@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {

RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}

}


3.继承KeyExpirationEventMessageListener创建redis过期事件的监听类

KeyExpirationEventMessageListener类是org.springframework.data.redis.listener包下的实现类,通过继承这个类重写onMessage方法可以实现对redis所有过期事件的监听。



@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer container) {
super(container);
}

/**
* 针对redis数据失效事件,进行数据处理
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String key=message.toString();//生效的key
if (key!=null && key.startsWith("order")){//从失效key中筛选代表订单失效的key
//截取订单号,查询订单,如果是未支付状态则取消订单
String orderNo=key.substring(5);
System.out.println("订单号为:"+orderNo+"的订单超时未支付,取消订单");

}
}
}


测试

通过redis模拟创建一个有效时间为5s的订单:

基于Redis过期事件实现订单超时取消_redis_02

 

 

5秒后程序成功监听到了过期事件:

基于Redis过期事件实现订单超时取消_spring_03