This commit is contained in:
2025-10-28 00:18:31 +08:00
parent 8905ce179c
commit 1c9c9cfa06
3 changed files with 203 additions and 2 deletions

105
Redis清理说明.md Normal file
View File

@@ -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天前的数据。

View File

@@ -3,6 +3,7 @@ package cn.van.business.controller.jd;
import cn.van.business.model.pl.TaobaoComment; import cn.van.business.model.pl.TaobaoComment;
import cn.van.business.repository.TaobaoCommentRepository; import cn.van.business.repository.TaobaoCommentRepository;
import cn.van.business.util.JDProductService; import cn.van.business.util.JDProductService;
import cn.van.business.util.JDScheduleJob;
import cn.van.business.util.JDUtil; import cn.van.business.util.JDUtil;
import cn.van.business.repository.CommentRepository; import cn.van.business.repository.CommentRepository;
import cn.van.business.model.pl.Comment; import cn.van.business.model.pl.Comment;
@@ -32,13 +33,15 @@ public class JDInnerController {
private final JDProductService jdProductService; private final JDProductService jdProductService;
private final JDUtil jdUtil; private final JDUtil jdUtil;
private final JDScheduleJob jdScheduleJob;
private final CommentRepository commentRepository; private final CommentRepository commentRepository;
private final TaobaoCommentRepository taobaoCommentRepository; private final TaobaoCommentRepository taobaoCommentRepository;
@Autowired @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.jdProductService = jdProductService;
this.jdUtil = jdUtil; this.jdUtil = jdUtil;
this.jdScheduleJob = jdScheduleJob;
this.commentRepository = commentRepository; this.commentRepository = commentRepository;
this.taobaoCommentRepository = taobaoCommentRepository; this.taobaoCommentRepository = taobaoCommentRepository;
} }
@@ -381,6 +384,30 @@ public class JDInnerController {
} }
} }
/**
* 手动清理Redis中超过93天的旧数据
* 请求参数:{ skey }
* 返回:{ message, success }
*/
@PostMapping("/cleanRedisData")
public Object cleanRedisData(@RequestBody Map<String, Object> 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) { private static JSONObject error(String msg) {
JSONObject o = new JSONObject(); JSONObject o = new JSONObject();

View File

@@ -28,7 +28,6 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId; 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<String> 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键清理完成 ===");
}
} }