From 1c9c9cfa062e04d6138ddc9272ffe927de7b63f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=92?= Date: Tue, 28 Oct 2025 00:18:31 +0800 Subject: [PATCH] 1 --- Redis清理说明.md | 105 ++++++++++++++++++ .../controller/jd/JDInnerController.java | 29 ++++- .../cn/van/business/util/JDScheduleJob.java | 71 +++++++++++- 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 Redis清理说明.md diff --git a/Redis清理说明.md b/Redis清理说明.md new file mode 100644 index 0000000..b070073 --- /dev/null +++ b/Redis清理说明.md @@ -0,0 +1,105 @@ +# Redis键清理功能说明 + +## 功能概述 +本功能用于清理Redis中超过93天(3个月)的旧数据,支持两种类型的键: +1. **tag键**:格式为 `tag:hash值:YYYY-MM-DD HH`,例如 `tag:01381d95e4936f1f3fe643bba2171894:2025-01-12 00` +2. **jd:refresh:tag键**:格式为 `jd:refresh:tag:hash值:YYYY-MM-DD HH:mm:ss` 或 `jd:refresh:tag:YYYY-MM-DD HH:mm:ss` + +## 使用方式 + +### 方式一:手动调用API接口(推荐) + +发送POST请求到:`http://your-server:port/jd/cleanRedisData` + +**请求示例:** +```bash +curl -X POST http://localhost:8080/jd/cleanRedisData \ + -H "Content-Type: application/json" \ + -d '{ + "skey": "2192057370ef8140c201079969c956a3" + }' +``` + +**响应示例:** +```json +{ + "success": true, + "message": "Redis清理任务已执行完成,详情请查看日志" +} +``` + +### 方式二:使用Postman等工具 + +1. 创建新的POST请求 +2. URL: `http://localhost:8080/jd/cleanRedisData` +3. Headers: `Content-Type: application/json` +4. Body (raw JSON): +```json +{ + "skey": "2192057370ef8140c201079969c956a3" +} +``` + +### 方式三:自动定时执行 + +系统已配置定时任务,每天凌晨3点自动执行清理: +- **tag键清理**:每天凌晨3点执行(cron: `0 0 3 * * ?`) +- **jd:refresh:tag键清理**:每月1日11:45执行(cron: `0 45 11 * * ?`) + +## 清理规则 + +- **截止日期**:当前时间减去93天 +- **清理对象**:所有早于截止日期的键 +- **安全性**:只删除符合特定格式且过期的键 + +例如: +- 当前时间:2025-10-27 +- 截止日期:2025-07-26 +- 将删除:2025-07-26之前的所有符合格式的键 +- 保留:2025-07-26及之后的键 + +## 日志查看 + +清理任务执行时会输出详细日志,可通过以下日志查看执行情况: + +``` +开始清理93天前的tag键数据,截止时间:YYYY-MM-DD HH:mm:ss +找到 X 个tag相关的键 +已删除 100 个过期的tag键 +已删除 200 个过期的tag键 +... +tag键清理完成,共删除 X 个过期键 +``` + +## 注意事项 + +1. **skey验证**:调用接口需要提供正确的skey(密钥) +2. **执行时间**:建议在业务低峰期手动执行清理,避免影响性能 +3. **备份建议**:首次执行前建议备份Redis数据 +4. **监控日志**:执行后及时查看日志,确认清理结果 + +## 代码位置 + +- **清理逻辑**:`d:\code\jd\src\main\java\cn\van\business\util\JDScheduleJob.java` + - `cleanOldTagRedisData()` - 清理tag键 + - `cleanOldRedisHashData()` - 清理jd:refresh:tag键 + - `manualCleanOldRedisData()` - 手动触发清理 + +- **API接口**:`d:\code\jd\src\main\java\cn\van\business\controller\jd\JDInnerController.java` + - `/jd/cleanRedisData` - POST接口 + +## 常见问题 + +**Q: 如何查看当前Redis中有多少符合条件的键?** +A: 可以使用Redis命令: +```bash +redis-cli KEYS "tag:*" | wc -l +redis-cli KEYS "jd:refresh:tag:*" | wc -l +``` + +**Q: 清理后可以恢复吗?** +A: 不可以,删除操作是不可逆的,请谨慎操作。 + +**Q: 如果需要调整清理天数怎么办?** +A: 修改 `JDScheduleJob.java` 中的 `minusDays(93)` 参数,例如改为 `minusDays(60)` 清理60天前的数据。 + diff --git a/src/main/java/cn/van/business/controller/jd/JDInnerController.java b/src/main/java/cn/van/business/controller/jd/JDInnerController.java index f855de2..f138e60 100644 --- a/src/main/java/cn/van/business/controller/jd/JDInnerController.java +++ b/src/main/java/cn/van/business/controller/jd/JDInnerController.java @@ -3,6 +3,7 @@ package cn.van.business.controller.jd; import cn.van.business.model.pl.TaobaoComment; import cn.van.business.repository.TaobaoCommentRepository; import cn.van.business.util.JDProductService; +import cn.van.business.util.JDScheduleJob; import cn.van.business.util.JDUtil; import cn.van.business.repository.CommentRepository; import cn.van.business.model.pl.Comment; @@ -32,13 +33,15 @@ public class JDInnerController { private final JDProductService jdProductService; private final JDUtil jdUtil; + private final JDScheduleJob jdScheduleJob; private final CommentRepository commentRepository; private final TaobaoCommentRepository taobaoCommentRepository; @Autowired - public JDInnerController(JDProductService jdProductService, JDUtil jdUtil, CommentRepository commentRepository, TaobaoCommentRepository taobaoCommentRepository) { + public JDInnerController(JDProductService jdProductService, JDUtil jdUtil, JDScheduleJob jdScheduleJob, CommentRepository commentRepository, TaobaoCommentRepository taobaoCommentRepository) { this.jdProductService = jdProductService; this.jdUtil = jdUtil; + this.jdScheduleJob = jdScheduleJob; this.commentRepository = commentRepository; this.taobaoCommentRepository = taobaoCommentRepository; } @@ -381,6 +384,30 @@ public class JDInnerController { } } + /** + * 手动清理Redis中超过93天的旧数据 + * 请求参数:{ skey } + * 返回:{ message, success } + */ + @PostMapping("/cleanRedisData") + public Object cleanRedisData(@RequestBody Map body) { + String skey = body.get("skey") != null ? String.valueOf(body.get("skey")) : null; + if (checkSkey(skey)) { + return error("invalid skey"); + } + try { + logger.info("手动触发Redis清理任务"); + jdScheduleJob.manualCleanOldRedisData(); + JSONObject resp = new JSONObject(); + resp.put("success", true); + resp.put("message", "Redis清理任务已执行完成,详情请查看日志"); + return resp; + } catch (Exception e) { + logger.error("cleanRedisData error", e); + return error("cleanRedisData failed: " + e.getMessage()); + } + } + private static JSONObject error(String msg) { JSONObject o = new JSONObject(); diff --git a/src/main/java/cn/van/business/util/JDScheduleJob.java b/src/main/java/cn/van/business/util/JDScheduleJob.java index 7c41620..ac4b659 100644 --- a/src/main/java/cn/van/business/util/JDScheduleJob.java +++ b/src/main/java/cn/van/business/util/JDScheduleJob.java @@ -28,7 +28,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; -import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; @@ -655,4 +654,74 @@ public void cleanOldRedisHashData() { } } +/** + * 清理tag:hash:时间 格式的Redis键(按小时),删除93天前的数据 + * 可以手动调用或定时执行 + */ +@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行 +public void cleanOldTagRedisData() { + try { + // 获取93天前的时间 + LocalDateTime ninetyThreeDaysAgo = LocalDateTime.now().minusDays(93); + int deletedCount = 0; + + logger.info("开始清理93天前的tag键数据,截止时间:{}", ninetyThreeDaysAgo.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + + // 获取所有以"tag:"开头的键 + Set tagKeys = redisTemplate.keys("tag:*"); + + if (tagKeys != null && !tagKeys.isEmpty()) { + logger.info("找到 {} 个tag相关的键", tagKeys.size()); + + for (String key : tagKeys) { + try { + // 处理格式:tag:hash值:YYYY-MM-DD HH + // 例如:tag:01381d95e4936f1f3fe643bba2171894:2025-01-12 00 + if (key.matches("tag:[a-f0-9]{32}:[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}")) { + // 提取时间部分(最后一个冒号之后) + String timePart = key.substring(key.lastIndexOf(":") + 1); + + LocalDateTime time; + try { + // 解析为小时级别的时间格式 yyyy-MM-dd HH + time = LocalDateTime.parse(timePart + ":00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } catch (DateTimeParseException e) { + logger.warn("无法解析Redis键时间:{},时间部分:{}", key, timePart); + continue; + } + + // 检查是否在93天前 + if (time.isBefore(ninetyThreeDaysAgo)) { + redisTemplate.delete(key); + deletedCount++; + if (deletedCount % 100 == 0) { + logger.info("已删除 {} 个过期的tag键", deletedCount); + } + } + } + } catch (Exception e) { + logger.warn("解析Redis tag键时间失败:{}", key, e); + } + } + + logger.info("tag键清理完成,共删除 {} 个过期键", deletedCount); + } else { + logger.info("未找到tag相关的键"); + } + } catch (Exception e) { + logger.error("清理tag Redis数据时发生错误", e); + } +} + +/** + * 手动执行清理方法(通过接口调用) + * 清理所有超过93天的tag键和jd:refresh:tag键 + */ +public void manualCleanOldRedisData() { + logger.info("=== 手动触发Redis键清理 ==="); + cleanOldTagRedisData(); + cleanOldRedisHashData(); + logger.info("=== Redis键清理完成 ==="); +} + }