利用Redis实现付款倒计时
一、前言
文本源自 微博客 且已获授权,请尊重知识产权。
公司项目最近在做一个交易系统,需要实现用户下订单以后一定时间内,不付款自动取消该订单
,这种功能也是涉及到交易的系统很常见的需求,那么应该如何实现呢?
二、思路
为了实现上述需求,我们可以使用Redis的订阅功能,在用户创建订单的时候,保存订单信息、设置过期时间,并且订阅该缓存信息;在这段过期时间期间内,如果用户付款,那么就删除该缓存信息,否则等到缓存过期时,取消该订单。具体实现如下:
三、具体实现
3.1 设置缓存
//订单倒计时开始 ORDER_INFO_COUNTDOWN 是一个字符串变量
redisCache.setCacheObject(ORDER_INFO_COUNTDOWN + order.getId(), "pending", 30, TimeUnit.MINUTES);
3.2 订阅失效事件
import com.acceptance.business.service.IAccOrderInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Objects;
import static com.acceptance.common.constant.CacheConstants.ORDER_INFO_COUNTDOWN;
@Log4j2
@Component
@RequiredArgsConstructor
public class OrderExpirationListener implements MessageListener {
private final RedisTemplate<Object, Object> redisTemplate;
private final IOrderInfoService orderService;
@PostConstruct
public void init() {
// 订阅键过期事件
Objects.requireNonNull(redisTemplate.getConnectionFactory())
.getConnection()
.pSubscribe(this, "__keyevent@*__:expired".getBytes());
}
@Override
public void onMessage(Message message, byte[] pattern) {
// 将消息体从字节数组转换为字符串
String channel = new String(message.getChannel());
String expiredKey = new String(message.getBody());
if (!(channel.startsWith("__keyevent@") && channel.endsWith(":expired"))) {
return;
}
// 检查频道名称是否符合预期
if (!expiredKey.startsWith(ORDER_INFO_COUNTDOWN)) {
return;
}
// 处理订单过期逻辑
long orderId = Long.parseLong(expiredKey.split(":")[1]);
log.info("监听到有未付款订单,准备自动取消....,id为:{}", orderId);
orderService.autoCancel(orderId, "过期未付款,系统自动取消");
//确保下次不会重复执行
redisTemplate.delete(ORDER_INFO_COUNTDOWN + orderId);
}
}
如果在这期间,用户对该订单付款,那么删除该缓存就好,经过上述步骤,即可实现订单倒计时功能,也是最简单的实现方法。
PS:为了实现订阅redis失效事件,还需要对redis进行设置:
登录redis-cli以后,执行以下命令:CONFIG SET notify-keyspace-events Ex