还可以使用rabbitMQ延时队列来处理,相对而言,个人觉得rabbitmq处理会更加稳定,毕竟redis的监听是包括全局所有的key的,redis 产生 expired 通知的时间为过期的key被删除的时候,但是当key的生存时间为0时,redis不能保证这个key会立即被删除
先将配置文件进行修改
搜索 notify-keyspace-events 配置一下键过期的参数, 修改成下图
notify-keyspace-events前面千万千万不能留有空格,我图片那样配置后出现读取配置文件错误。 配置完需要重启一下redis的服务使配置生效
yml文件中redis的配置
pom依赖
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
* 注册redisTemplate
*/
@Configuration
public class RedisConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
}
redis监听类
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* 订单过期监听:接收过期的redis消息,获取到key(订单号)
* 然后去更新对应订单状态
*/
@Transactional
@Component
@Slf4j
public class RedisListener extends KeyExpirationEventMessageListener {
@Autowired
private ScalpOrderService scalpOrderService;
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
*监听失效的key
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
// 获取失效的key
String expiredKey = message.toString();
String prefix = "";
if(expiredKey.indexOf("_") != -1){
prefix = expiredKey.substring(0,expiredKey.indexOf("_"));
}
//根据key的前缀判断是否属于订单过期
if("order".equals(prefix)){
String orderId = expiredKey.substring(expiredKey.indexOf("_") + 1);
//业务逻辑处理
ScalpOrder order = scalpOrderService.getById(orderId);
//将订单状态更改为超时
order.setOrderStatus(UsedCode.ORDER_PAST_DUE);
scalpOrderService.updateById(order);
//处理订单冻结信息
scalpOrderService.putFreezeMoney(order,UsedCode.ORDER_PAST_DUE,Object->{
log.info("订单号:{}已超时" ,expiredKey);
return Result.ok();
});
}
}
}
设置订单的过期时间为30分钟
redisUtil.ins("order_"+orderId,orderId,30, TimeUnit.MINUTES);
redisUtil
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 读取缓存
*
* @param key
* @return
*/
public String get(final String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 写入缓存
*/
public boolean ins(final String key, String value,int time,TimeUnit unit) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value,time, unit);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public boolean expire(String key, long time) {
try {
if (time > 0L) {
this.redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception var5) {
var5.printStackTrace();
return false;
}
}
/**
* 删除缓存
*/
public boolean delete(final String key) {
boolean result = false;
try {
redisTemplate.delete(key);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
}
测试结果