文章目录
前言
在现代分布式系统中,会话管理和延迟任务处理是两个核心需求。本文将深入探讨如何利用 Redisson 解决这两个问题,通过代码实战演示分布式会话共享和订单超时未支付的延迟任务处理。
一、为什么需要分布式会话管理?
在单机应用中,Session 存储在内存中。但在分布式环境下,请求可能被负载均衡到不同服务器,导致 Session 丢失。解决方案:将会话数据集中存储在 Redis 中,实现多服务共享。
1.1 使用 Redisson 实现 Session 共享
实现原理:
将会话数据存储在 Redis Hash 结构中,利用 Redisson 的分布式对象操作 API 实现透明化存取。
Maven 依赖:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.2</version>
</dependency>
配置 Redisson 客户端:
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
}
会话管理服务:
@Service
public class SessionService {
@Autowired
private RedissonClient redissonClient;
// 存储会话数据
public void putSession(String sessionId, String key, Object value) {
RMap<String, Object> sessionMap = redissonClient.getMap("session:" + sessionId);
sessionMap.put(key, value);
// 设置会话过期时间(30分钟)
sessionMap.expire(30, TimeUnit.MINUTES);
}
// 获取会话数据
public Object getSession(String sessionId, String key) {
RMap<String, Object> sessionMap = redissonClient.getMap("session:" + sessionId);
return sessionMap.get(key);
}
// 销毁会话
public void invalidateSession(String sessionId) {
redissonClient.getMap("session:" + sessionId).delete();
}
}
Controller 中使用示例:
@RestController
public class AuthController {
@Autowired
private SessionService sessionService;
@PostMapping("/login")
public String login(@RequestBody User user, HttpServletRequest request) {
// 验证用户逻辑...
String sessionId = request.getSession().getId();
sessionService.putSession(sessionId, "user", user);
return "Login success! Session: " + sessionId;
}
@GetMapping("/profile")
public User profile(HttpServletRequest request) {
String sessionId = request.getSession().getId();
return (User) sessionService.getSession(sessionId, "user");
}
}
二、订单超时未支付?用延迟队列精准处理
电商场景中,订单创建后需在 30 分钟内支付,否则自动关闭。传统轮询数据库方案效率低下,Redisson 的 RDelayedQueue 是完美解决方案。
2.1 RDelayedQueue 核心机制
2.2 订单超时处理实战
订单服务实现:
@Service
public class OrderService {
@Autowired
private RedissonClient redissonClient;
// 创建订单并加入延迟队列
public void createOrder(Order order) {
// 1. 保存订单到数据库(状态:待支付)
orderRepository.save(order);
// 2. 加入延迟队列(30分钟超时)
RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue("ORDER_EXPIRE_QUEUE");
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
delayedQueue.offer(order.getId(), 30, TimeUnit.MINUTES);
}
// 监听订单超时队列
@PostConstruct
public void startExpireListener() {
new Thread(() -> {
RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue("ORDER_EXPIRE_QUEUE");
while (true) {
try {
String orderId = blockingQueue.take(); // 阻塞获取到期订单
handleExpiredOrder(orderId);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}).start();
}
// 处理过期订单
private void handleExpiredOrder(String orderId) {
Order order = orderRepository.findById(orderId).orElse(null);
if (order != null && "UNPAID".equals(order.getStatus())) {
order.setStatus("CANCELED");
order.setCancelReason("支付超时");
orderRepository.save(order);
System.out.println("订单超时关闭: " + orderId);
// 释放库存等后续操作...
}
}
}
支付回调逻辑:
public void onPaymentSuccess(String orderId) {
// 1. 更新订单状态为已支付
Order order = orderRepository.findById(orderId).get();
order.setStatus("PAID");
orderRepository.save(order);
// 2. 从延迟队列中移除(避免重复处理)
RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(
redissonClient.getBlockingQueue("ORDER_EXPIRE_QUEUE")
);
delayedQueue.remove(orderId); // 关键:支付成功则移除任务
}
总结
通过本文实战,我们实现了:
- 分布式会话管理:利用 RMap 存储会话数据,解决集群环境 Session 共享问题
- 精准延迟任务:基于 RDelayedQueue 实现订单超时自动关闭,替代低效轮询方案
Redisson 的强大之处在于将复杂的分布式问题抽象为简单的 API 调用。这两个方案可扩展到更多场景:
- 会话管理 → 分布式权限系统
- 延迟队列 → 定时通知、预约系统