如何优雅的通过Spring Boot+Redission对订单实现定时关闭

发布于:2024-10-13 ⋅ 阅读:(6) ⋅ 点赞:(0)

简介

在电子商务及支付相关平台中,常规流程是首先生成订单或支付请求,用户随后会在规定时间内完成支付。如果用户未能在预设时限内完成支付动作,系统通常会执行相应的过期处理机制,即自动取消未支付的订单。

此外,这类系统还设置了多种自动化业务规则来处理其他时效性较强的场景,例如:

  1. 到期自动确认收货:当商品配送预计到达时间过后,若用户未主动确认收货,系统将自动视为用户已收货并触发后续评价或售后环节。
  2. 超时自动退款:对于某些未及时处理的退款申请,或者因物流异常等原因导致的退款,系统在达到预设等待期限后会自动退还消费者款项。
  3. 下单后自动通知:一旦用户下单成功,系统会自动触发短信或邮件通知服务,向用户发送订单确认信息或其他相关信息。

以上这些功能都是为了提高系统的自动化水平和用户体验,减少人工干预的需求,并确保交易过程顺畅高效

实现方式

被动关闭(不推荐)

在电子商务系统中,一旦创建了订单,系统并不会主动介入进行关闭操作,而是静待用户行为,仅当用户实际访问或查询订单状态时,系统才会实时进行评估,以判断是否满足应当关闭订单的条件。缺点就是如果用户一直没有访问订单则会导致订单一直处于未关闭的状态,这时数据库中会堆积大量垃圾数据

@Slf4j
@Service
public class PassiveShutdownServiceImpl implements OrderShutdown {

    @Autowired
    private OrderMapper orderMapper;
    /**
     * 方法一:被动关闭
     */
    @Override
    public void orderShutdown() {
        //假设订单id为1
        Long orderId = 1L;
        Order order = orderMapper.findOrderById(orderId);
        //省略其他相关业务判断......
        //判断当前是否大于到期时间
        if(order.getExpireTime().compareTo(new Date())==-1){
            //修改订单状态
            log.info("当前时间大于到期时间");
            int result = orderMapper.updateOrderStatus(orderId);
            //省略判断是否修改成功相关逻辑
        }
    }
}
<select id="findOrderById" resultType="com.yiridancan.delayShutdown.entity.Order" parameterType="long">
        select * from t_order where id=#{orderId} and order_status!='CLOSED'
</select>

<update id="updateOrderStatus" parameterType="long">
        update t_order set  order_status='CLOSED' where id=#{orderId}
</update>

测试代码:

@SpringBootTest
class DelayShutdownApplicationTests {

	@Autowired
	private PassiveShutdownServiceImpl passiveShutdownService;

	/** 
	 *  延期关闭测试类。通过策略模式指定方法
	 * @author yiridancan
	 * @date 2024/4/3 22:56
	 */
	@Test
	void delayShutdown() {
		OrderShutdown orderShutdown = passiveShutdownService;
		orderShutdown.orderShutdown();
	}

}

定时任务(推荐,适用于时间精准度不高的场景)

定时任务就是定时去扫描表中数据进行订单关闭,实现比较简单,就不提供具体示例代码

缺点:

  • 时间不精准,如果一个订单到了关闭时间,但定时任务时间还没到,就会导致订单一直没有关闭
  • 无法处理大订单量:如果数据量大的情况下,那么就有可能导致任务执行时间很长,订单被扫描到时间可能就很晚,那么就会导致关闭时间更晚
  • 数据库压力大:定时任务扫描表数据,会占用数据库的IO资源。严重时会导致线上的正常业务

Redission(推荐)

Redisson是一个在Redis的基础上实现的框架,它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。可以通过Redission中的RDelayedQueue延迟队列实现订单到期关闭,它可以用于在指定的时间后执行某些操作。底层主要是用到了Redis的zset数据结构,并且在这基础上增加了一个延迟队列。我们要添加一个数据到延迟队列的时候,redisson会把数据+超时时间放到zset中,并且起一个延时任务,当任务到期的时候,再去zset中把数据取出来,返回给客户端使用。

1.添加依赖

2.配置Redission

创建一个Redission配置类,用于创建Redission

3.创建订单服务

创建一个订单服务类,使用 RDelayedQueue 来实现订单到期关闭的逻辑:

4.创建订单

创建订单controller层,用于模拟订单创建并设置关闭时间

5.启动应用

启动应用并访问http://ip:host/orders/create?expireTime=关闭时间进行默认订单创建

运行效果

创建订单成功:

Redis队列数据:

到期关闭结果:

  可见2分钟后订单id为:2024-10-12 13:43:21定时关闭了

6.注意事项

  1.  确保Redis服务器正在运行
  2. 根据需要调整延迟时间和其他业务逻辑
  3. 处理并发和异常处理,以确保在实际环境中的可靠性
  4. 如遇到以下异常,升级Redis版本进行处理

Redission案例源码地址:如何优雅的通过SpringBoot+Redission对订单实现定时关闭资源-CSDN文库

总结

这里只列举了部分实现方式,比如还可以通过MQ(不推荐,会有大量无效调度数据)、时间轮、Redis的过期监听等。不同的场景适用于不同的技术方案,没有决定的技术

在CSDN上,一键三连是对作者辛勤创作的最好鼓励!喜欢我的文章,就请点赞、收藏、转发吧!你们的支持是我持续分享知识的动力,感谢大家的陪伴与认可!💖🔝🔄