【项目实战】Redis使用场景之待支付订单自动取消、订单自动收货

编程入门 行业动态 更新时间:2024-10-25 11:26:59

一、使用背景

很多业务场景,例如订单过期自动删除,订单几天后自动好评,这些常用操作可以通过定时任务,数据库轮询做,但是订单量大的情况可能会对数据库产生大的压力。

二、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),监听器再判断处理该订单是否需要取消

    @Overridepublic 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);}

更多推荐

订单,收货,实战,场景,项目

本文发布于:2023-05-20 23:50:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/156738.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:订单   收货   实战   场景   项目

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!