【项目实战】Redis使用场景之待支付订单自动取消、订单自动收货
2023-09-14 09:14:14 时间
一、使用背景
很多业务场景,例如订单过期自动删除,订单几天后自动好评,这些常用操作可以通过定时任务,数据库轮询做,但是订单量大的情况可能会对数据库产生大的压力。
二、Redis的key过期推送功能原理分析
Redis的key过期推送功能打开后,程序通过监听器(RedisKeyExpirationListener.java)监听到每个key过期的事件,再做相应处理。
三、打开Redis的key过期推送的正确方式
3.1 为什么要打开?
事件通过 Redis 的订阅与发布功能(pub/sub)来进行分发,故需要开启 redis 的事件监听与发布。
3.2 如何打开?
可以改 redis.conf 文件 打开 notify-keyspace-events Ex 的注释,开启过期通知功能
比如,可以使用 config set notify-keyspace-events Exe
命令来打开 Redis 的 key 过期推送通知。
其中,Ex 表示所有事件都通知,e 表示只通知 key 过期事件。
执行该命令后,可以使用订阅类型的命令(如 PSUBSCRIBE)订阅通知。
四、功能实战1 :待支付订单自动取消功能
步骤1:将该订单相关信息存入Redis
生成新订单时,将该订单相关信息存入redis,并设置过期时间
//加入redis,30分钟自动取消
String keyRedis = String.valueOf(StrUtil.format("{}{}:{}",MallConstants.REDIS_ORDER_KEY_IS_PAY_0,TenantContextHolder.getTenantId(),orderInfo.getId()));
//设置过期时间
redisTemplate.opsForValue().set(keyRedis, orderInfo.getOrderNo() , orderTimeOut , TimeUnit.MINUTES);
步骤2:编写监听器判断订单到期逻辑
当此key值的订单到期时,redis通知到监听器(RedisKeyExpirationListener.java),监听器再判断处理该订单是否需要取消
@Override
public void onMessage(Message message, byte[] bytes) {
RedisSerializer<?> serializer = redisTemplate.getValueSerializer();
String channel = String.valueOf(serializer.deserialize(message.getChannel()));
String body = String.valueOf(serializer.deserialize(message.getBody()));
//key过期监听
if(StrUtil.format("__keyevent@{}__:expired", redisConfigProperties.getDatabase()).equals(channel)){
//订单自动取消
if(body.contains(MallConstants.REDIS_ORDER_KEY_IS_PAY_0)) {
body = body.replace(MallConstants.REDIS_ORDER_KEY_IS_PAY_0, "");
String[] str = body.split(":");
String wxOrderId = str[1];
TenantContextHolder.setTenantId(str[0]);
OrderInfo orderInfo = orderInfoService.getById(wxOrderId);
if(orderInfo != null && CommonConstants.NO.equals(orderInfo.getIsPay())){//只有待支付的订单能取消
orderInfoService.orderCancel(orderInfo);
}
}
......
}
}
五、功能实战2 : 订单自动收货
步骤1:定义常量
/**
* 订单自动收货时间(天)
*/
long ORDER_TIME_OUT_2 = 7;
步骤2:编写业务逻辑
@Slf4j
@Service
@AllArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {
private final OrderItemService orderItemService;
private final OrderLogisticsService orderLogisticsService;
private final RedisTemplate<String, String> redisTemplate;
private final MallConfigProperties mallConfigProperties;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateById(OrderInfo entity) {
if (StrUtil.isNotBlank(entity.getLogistics()) && StrUtil.isNotBlank(entity.getLogisticsNo())) {// 发货。更新快递单号
entity.setDeliveryTime(LocalDateTime.now());
OrderLogistics orderLogistics = orderLogisticsService
.getOne(Wrappers.<OrderLogistics>lambdaQuery().eq(OrderLogistics::getId, entity.getLogisticsId()));
// 第一次发货调起收到倒计时
boolean sendRedis = false;
if (StrUtil.isBlank(orderLogistics.getLogistics()) && StrUtil.isBlank(orderLogistics.getLogisticsNo())) {
sendRedis = true;
}
orderLogistics.setLogistics(entity.getLogistics());
orderLogistics.setLogisticsNo(entity.getLogisticsNo());
orderLogistics.setStatus(OrderLogisticsEnum.STATUS_1.getValue());
mallConfigProperties.getLogistics().forEach(logistics -> {
if (StrUtil.equals(logistics.getCode(), entity.getLogistics())) {
orderLogistics.setLogisticsDesc(logistics.getName());
}
});
orderLogisticsService.updateById(orderLogistics);
if (sendRedis) {
// 加入redis,7天后自动确认收货
String keyRedis = String.valueOf(StrUtil.format("{}{}:{}", MallConstants.REDIS_ORDER_KEY_STATUS_2,
TenantContextHolder.getTenantId(), entity.getId()));
redisTemplate.opsForValue().set(keyRedis, entity.getOrderNo(), MallConstants.ORDER_TIME_OUT_2,
TimeUnit.DAYS);// 设置过期时间
}
}
return super.updateById(entity);
}
相关文章
- Redis事务:实现自动回滚(redis事务回滚)
- 实现Redis自动启动的简易方法(redis设置自启动)
- Redis分布式集群实现数据同步(redis集群数据同步)
- 虚拟机上实现Redis自动启动服务(虚拟机redis自启动)
- 无Redis若依如何重生(若依去掉redis)
- 查看Redis队列中所有值的实战经验(查看redis队列所有值)
- 超高性能百万级Redis数据查询(百万级数据查询redis)
- 深入探索查看Redis环境变量(查看redis环境变量)
- 如何设置实现Redis自动启动(怎么自动启动redis库)
- 如何使用Redis实现多项目的隔离(多项目redis怎样区分)
- 学习Redis步步深入理解(如何学会redis)
- 通过Redis实现高性能编码(redis高性能写法)
- 查询分析Redis在高并发时慢查询的原因(redis高并发时慢)
- 从零开始实施Redis项目部署(redis项目部署)
- Redis面试通向梦想的里程碑第七步(redis面试p7)
- 红色之火Redis集群节点的出色之处(redis集群节点特性)
- 最佳的Redis集群基于阿里云搭建(redis 阿里云集群)
- 部署项目从Redis到实现(redis 部署项目)
- Redis的自动动态过期时间预估(redis过期时间预估)
- 学习Redis课程开启NoSQL之旅(redis课程内容)
- Redis读写达到极限高性能持续增长(redis 读写极限)
- Redis实现订单自动过期处理(redis 订单过期触发)
- Redis超神自动清空缓存的秘诀(redis 自动清除缓存)
- 利用Redis简化网站自动关闭流程(redis 网站自动关闭)
- 揭示Redis缓存的项目应用(redis缓存的项目描述)
- Redis进程深入探究(redis涉及到的进程)