java订单到期自动取消_生成订单后一段时间不支付订单会自动关闭的功能该如何实现?...

本文介绍了如何利用Redis的键过期事件实现订单超时自动取消功能。通过在生成订单时设置Redis键值对的过期时间,然后监听过期队列,当订单键值对过期时执行关闭订单的操作,以此提高系统效率。
摘要由CSDN通过智能技术生成

业务场景

我们以订单功能为例说明下:生成订单后一段时间不支付订单会自动关闭。最简单的想法是设置定时任务轮询,但是每个订单的创建时间不一样,定时任务的规则无法设定,如果将定时任务执行的间隔设置的过短,太影响效率。还有一种想法,在用户进入订单界面的时候,判断时间执行相关操作。方式可能有很多,在这里介绍一种监听 Redis 键值对过期时间来实现订单自动关闭

实现思路

在生成订单时,向 Redis 中增加一个 KV 键值对,K 为订单号,保证通过 K 能定位到数据库中的某个订单即可,V 可为任意值。假设,生成订单时向 Redis 中存放 K 为订单号,V 也为订单号的键值对,并设置过期时间为 30 分钟,如果该键值对在 30 分钟过期后能够发送给程序一个通知,或者执行一个方法,那么即可解决订单关闭问题。实现:通过监听 Redis 提供的过期队列来实现,监听过期队列后,如果 Redis 中某一个 KV 键值对过期了,那么将向监听者发送消息,监听者可以获取到该键值对的 K,注意,是获取不到 V 的,因为已经过期了,这就是上面所提到的,为什么要保证能通过 K 来定位到订单,而 V 为任意值即可。拿到 K 后,通过 K 定位订单,并判断其状态,如果是未支付,更新为关闭,或者取消状态即可。

开启 Redis key 过期提醒

修改 redis 相关事件配置。找到 redis 配置文件 redis.conf,查看 notify-keyspace-events 配置项,如果没有,添加 notify-keyspace-events Ex,如果有值,则追加 Ex,相关参数说明如下:K:keyspace 事件,事件以 keyspace@ 为前缀进行发布

E:keyevent 事件,事件以 keyevent@ 为前缀进行发布

g:一般性的,非特定类型的命令,比如del,expire,rename等

$:字符串特定命令

l:列表特定命令

s:集合特定命令

h:哈希特定命令

z:有序集合特定命令

x:过期事件,当某个键过期并删除时会产生该事件

e:驱逐事件,当某个键因 maxmemore 策略而被删除时,产生该事件

A:g$lshzxe的别名,因此”AKE”意味着所有事件

引入依赖

在 pom.xml 中添加 org.springframework.boot:spring-boot-starter-data-redis 依赖

org.springframework.boot

spring-boot-starter-data-redis

复制代码

相关配置

定义配置 RedisListenerConfig 实现监听 Redis key 过期时间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;

}

}

复制代码

定义监听器 RedisKeyExpirationListener,实现KeyExpirationEventMessageListener 接口,查看源码发现,该接口监听所有 db 的过期事件 keyevent@*:expired"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;

/**

* 监听所有db的过期事件__keyevent@*__:expired"

*/

@Component

public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {

super(listenerContainer);

}

/**

* 针对 redis 数据失效事件,进行数据处理

* @param message

* @param pattern

*/

@Override

public void onMessage(Message message, byte[] pattern) {

// 获取到失效的 key,进行取消订单业务处理

String expiredKey = message.toString();

System.out.println(expiredKey);

}

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您演示如何使用Spring Boot、MyBatis、MySQL和Redis实现订单在指定时间内没有完成支付自动取消订单功能。 首先,我们需要定义订单实体类,包含订单号、订单状态、创建时间、过期时间等属性。 ```java public class Order { private Long id; private String orderNo; private Integer status; private Date createTime; private Date expireTime; // 省略getter和setter方法 } ``` 然后我们需要在MySQL数据库中创建订单表,用于存储订单信息。 ```sql CREATE TABLE `order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL, `status` int(11) NOT NULL, `create_time` datetime NOT NULL, `expire_time` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ``` 接着,我们需要使用MyBatis来实现订单表的增删改查操作,以及定时任务更新订单状态的操作。这些操作可以通过Mapper接口和Mapper.xml文件来实现。在Mapper.xml文件中,我们可以使用MySQL的定时任务机制,定期执行更新操作,将过期的订单状态改为已取消。 ```xml <!-- OrderMapper.xml --> <mapper namespace="com.example.demo.mapper.OrderMapper"> <insert id="insertOrder" parameterType="Order"> insert into `order` (order_no, status, create_time, expire_time) values (#{orderNo}, #{status}, #{createTime}, #{expireTime}) </insert> <update id="cancelOrder" parameterType="Order"> update `order` set status = #{status} where id = #{id} </update> <select id="getOrderById" parameterType="Long" resultType="Order"> select * from `order` where id = #{id} </select> <update id="updateExpiredOrderStatus"> update `order` set status = #{status} where status = #{oldStatus} and expire_time <= #{now} </update> </mapper> ``` 在定时任务中,我们需要使用MyBatis的update方法来更新过期的订单状态。 ```java @Service public class OrderService { private final OrderMapper orderMapper; public OrderService(OrderMapper orderMapper) { this.orderMapper = orderMapper; } @Scheduled(cron = "0 */1 * * * ?") // 每分钟执行一次 public void updateExpiredOrderStatus() { Order order = new Order(); order.setStatus(OrderStatusEnum.CANCELED.getValue()); order.setOldStatus(OrderStatusEnum.UNPAID.getValue()); order.setNow(new Date()); orderMapper.updateExpiredOrderStatus(order); } } ``` 然后,我们需要使用Redis来实现订单状态的缓存。在订单创建时,将订单信息存储到Redis中,并设置过期时间订单的过期时间。当用户支付成功后,将Redis中的订单状态改为已支付。如果订单支付并且过期时间已到,则将Redis中的订单状态改为已取消,并通过MyBatis更新订单状态。 ```java @Configuration public class RedisConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.database}") private int database; @Bean public JedisPool jedisPool() { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(100); jedisPoolConfig.setMaxIdle(20); jedisPoolConfig.setMinIdle(10); jedisPoolConfig.setMaxWaitMillis(10000); return new JedisPool(jedisPoolConfig, host, port, timeout, password, database); } } @Service public class OrderService { private final OrderMapper orderMapper; private final JedisPool jedisPool; public OrderService(OrderMapper orderMapper, JedisPool jedisPool) { this.orderMapper = orderMapper; this.jedisPool = jedisPool; } public Order createOrder(Order order) { orderMapper.insertOrder(order); String key = "order:" + order.getId(); try (Jedis jedis = jedisPool.getResource()) { jedis.set(key, String.valueOf(OrderStatusEnum.UNPAID.getValue()), "NX", "EX", order.getExpireTime().getTime() / 1000); } return order; } public void payOrder(Long orderId) { String key = "order:" + orderId; try (Jedis jedis = jedisPool.getResource()) { jedis.set(key, String.valueOf(OrderStatusEnum.PAID.getValue())); } } } ``` 最后,我们需要使用Spring的定时任务来定期检查Redis中的订单状态,并对过期的订单进行处理。具体实现可以通过在Spring Boot应用程序中添加一个Scheduled注解方法来实现。 ```java @Service public class OrderService { private final OrderMapper orderMapper; private final JedisPool jedisPool; public OrderService(OrderMapper orderMapper, JedisPool jedisPool) { this.orderMapper = orderMapper; this.jedisPool = jedisPool; } @Scheduled(cron = "0 */1 * * * ?") // 每分钟执行一次 public void checkExpiredOrder() { try (Jedis jedis = jedisPool.getResource()) { Set<String> keys = jedis.keys("order:*"); if (keys != null && !keys.isEmpty()) { for (String key : keys) { String value = jedis.get(key); if (value != null) { Long orderId = Long.parseLong(key.split(":")[1]); Order order = orderMapper.getOrderById(orderId); if (order != null && order.getStatus() == OrderStatusEnum.UNPAID.getValue()) { if (new Date().after(order.getExpireTime())) { order.setStatus(OrderStatusEnum.CANCELED.getValue()); orderMapper.cancelOrder(order); jedis.del(key); } } else { jedis.del(key); } } } } } } } ``` 以上就是使用Spring Boot、MyBatis、MySQL和Redis实现订单在指定时间内没有完成支付自动取消订单的详细演示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值