Redis中的自动过期机制
前言
比如我们需要监听那些key已经过期,再进行对该数据进行下一步的业务处理。
实现需求:处理订单过期自动取消,比如下单15分钟未支付自动更改订单状态
实现方案:
1.使用Redis Key自动过期出发事件通知
2.使用定时任务15分钟后检查
3.按照每分钟轮训检查
1.使用Redis Key自动过期机制
当我们的key失效时,我们可以执行我们的客户端回调监听的方法。
需要在redis中配置:notify-keyspace-events “Ex”
2.Springboot整合key过期监听
2.1. 创建表 order_number
CREATE TABLE `order_number` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_name` varchar(255) DEFAULT NULL,
`order_status` int(11) DEFAULT NULL,
`order_token` varchar(255) DEFAULT NULL,
`order_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2.2核心代码
列举部分核心监控redis失效key的代码,详见github项目 :springboot-redis【redis-listener】
2.2.1 核心代码
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;
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
import com.redmaple.entity.OrderEntity;
import com.redmaple.mapper.OrderMapper;
import com.redmaple.service.OrderService;
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;
/**
* @description:
* @author: uwank171
* @date: 2022/9/2 14:40
*/
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
private final static String ORDER_ = "order_";
@Autowired
private OrderService orderService;
/**
* Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
*
* @param listenerContainer must not be {@literal null}.
*/
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* Redis失效事件 key
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
// 表示失效过期的key值
String expiraKey = message.toString();
System.out.println(">>>>> 过期的key: " + expiraKey);
// 做业务处理 TODO
if (expiraKey.startsWith(ORDER_)) {
orderService.doOrderExpireKey(expiraKey);
}
}
}
import com.redmaple.entity.OrderEntity;
import com.redmaple.mapper.OrderMapper;
import com.redmaple.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: uwank171
* @date: 2022/9/2 15:10
*/
@Service
public class OrderServiceImpl implements OrderService {
/**
* 待支付
*/
private static final Integer ORDER_STAYPAY = 0;
/**
* 失效
*/
private static final Integer ORDER_INVALID = 2;
@Autowired
private OrderMapper orderMapper;
/**
* 处理过期的key
*
* @param expiraKey
*/
@Override
public void doOrderExpireKey(String expiraKey) {
// 根据key查询 value 如果还还是为待支付状态 将订单改为已经超时~~
OrderEntity orderNumber = orderMapper.getOrderNumber(expiraKey);
System.out.println(expiraKey);
if (orderNumber == null) {
return;
}
if (orderNumber.getOrderStatus().equals(ORDER_STAYPAY)) {
// 将订单状态改为已经失效
orderMapper.updateOrderStatus(expiraKey, ORDER_INVALID);
}
System.out.println(">>>>> doOrderExpireKey 完成");
}
}
import com.redmaple.common.util.JedisUtil;
import com.redmaple.entity.OrderEntity;
import com.redmaple.mapper.OrderMapper;
import com.redmaple.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
public class OrderController {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderService orderService;
@Autowired
private JedisUtil jedisUtil;
private final static String ORDER_ = "order_";
@RequestMapping("/saveOrder")
public String saveOrder() {
// 1.生成token
String orderToken = ORDER_ + UUID.randomUUID().toString();
String orderId = System.currentTimeMillis() + "";
//2. 将该token存放到redis中
jedisUtil.set(orderToken, orderId);
jedisUtil.expire(orderToken, 10);
OrderEntity orderEntity = new OrderEntity(null, "C测试监听redis失效过期的key值", orderId, orderToken);
int result = orderMapper.insertOrder(orderEntity);
return result > 0 ? "success" : "fail";
}
}
2.2.2 maven核心依赖
<!-- SpringBoot-整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 集成lombok 框架 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- springboot-redis 和 jedis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Jedis 客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.2.3 application.yml
server:
port: 7000
spring:
redis:
database: 0
host: 172.28.13.140
port: 7000
password: China1234
timeout: 10000
jedis:
pool:
max-active: 500
min-idle: 5
max-idle: 50
max-wait: 60000
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
## 数据库
url: jdbc:mysql://127.0.0.1:3306/gi_test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
username: root
password: root
如果该文章能够帮助到你,希望麻烦点赞收藏下,谢谢