ai-engineering-init 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/code-reviewer.md +3 -130
- package/.claude/hooks/skill-forced-eval.js +46 -60
- package/.claude/hooks/stop.js +24 -1
- package/.claude/settings.json +10 -1
- package/.claude/skills/api-development/SKILL.md +179 -130
- package/.claude/skills/architecture-design/SKILL.md +102 -212
- package/.claude/skills/backend-annotations/SKILL.md +166 -220
- package/.claude/skills/bug-detective/SKILL.md +225 -186
- package/.claude/skills/code-patterns/SKILL.md +127 -244
- package/.claude/skills/codex-code-review/SKILL.md +327 -0
- package/.claude/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.claude/skills/crud-development/SKILL.md +226 -307
- package/.claude/skills/data-permission/SKILL.md +131 -202
- package/.claude/skills/database-ops/SKILL.md +158 -355
- package/.claude/skills/error-handler/SKILL.md +224 -285
- package/.claude/skills/file-oss-management/SKILL.md +174 -169
- package/.claude/skills/git-workflow/SKILL.md +123 -341
- package/.claude/skills/json-serialization/SKILL.md +121 -137
- package/.claude/skills/leniu-report-customization/SKILL.md +82 -2
- package/.claude/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/.claude/skills/loki-log-query/SKILL.md +400 -0
- package/.claude/skills/mysql-debug/SKILL.md +58 -22
- package/.claude/skills/performance-doctor/SKILL.md +83 -89
- package/.claude/skills/redis-cache/SKILL.md +134 -185
- package/.claude/skills/scheduled-jobs/SKILL.md +187 -224
- package/.claude/skills/security-guard/SKILL.md +168 -276
- package/.claude/skills/sms-mail/SKILL.md +266 -228
- package/.claude/skills/social-login/SKILL.md +257 -195
- package/.claude/skills/sync-back-merge/SKILL.md +66 -0
- package/.claude/skills/tenant-management/SKILL.md +172 -188
- package/.claude/skills/utils-toolkit/SKILL.md +214 -222
- package/.claude/skills/websocket-sse/SKILL.md +251 -172
- package/.claude/skills/workflow-engine/SKILL.md +178 -250
- package/.claude/skills/yunxiao-task-management/SKILL.md +489 -0
- package/.codex/skills/api-development/SKILL.md +179 -130
- package/.codex/skills/architecture-design/SKILL.md +102 -212
- package/.codex/skills/backend-annotations/SKILL.md +166 -220
- package/.codex/skills/bug-detective/SKILL.md +225 -186
- package/.codex/skills/code-patterns/SKILL.md +127 -244
- package/.codex/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.codex/skills/crud-development/SKILL.md +226 -307
- package/.codex/skills/data-permission/SKILL.md +131 -202
- package/.codex/skills/database-ops/SKILL.md +158 -355
- package/.codex/skills/error-handler/SKILL.md +224 -285
- package/.codex/skills/file-oss-management/SKILL.md +174 -169
- package/.codex/skills/git-workflow/SKILL.md +123 -341
- package/.codex/skills/json-serialization/SKILL.md +121 -137
- package/.codex/skills/leniu-report-customization/SKILL.md +82 -2
- package/.codex/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/.codex/skills/loki-log-query/SKILL.md +400 -0
- package/.codex/skills/loki-log-query/environments.json +45 -0
- package/.codex/skills/mysql-debug/SKILL.md +58 -22
- package/.codex/skills/performance-doctor/SKILL.md +83 -89
- package/.codex/skills/redis-cache/SKILL.md +134 -185
- package/.codex/skills/scheduled-jobs/SKILL.md +187 -224
- package/.codex/skills/security-guard/SKILL.md +168 -276
- package/.codex/skills/skill-creator/LICENSE.txt +202 -0
- package/.codex/skills/skill-creator/SKILL.md +479 -0
- package/.codex/skills/skill-creator/agents/analyzer.md +274 -0
- package/.codex/skills/skill-creator/agents/comparator.md +202 -0
- package/.codex/skills/skill-creator/agents/grader.md +223 -0
- package/.codex/skills/skill-creator/assets/eval_review.html +146 -0
- package/.codex/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.codex/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.codex/skills/skill-creator/references/schemas.md +430 -0
- package/.codex/skills/skill-creator/scripts/__init__.py +0 -0
- package/.codex/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.codex/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.codex/skills/skill-creator/scripts/improve_description.py +248 -0
- package/.codex/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.codex/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.codex/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.codex/skills/skill-creator/scripts/run_loop.py +332 -0
- package/.codex/skills/skill-creator/scripts/utils.py +47 -0
- package/.codex/skills/sms-mail/SKILL.md +266 -228
- package/.codex/skills/social-login/SKILL.md +257 -195
- package/.codex/skills/sync-back-merge/SKILL.md +66 -0
- package/.codex/skills/tenant-management/SKILL.md +172 -188
- package/.codex/skills/utils-toolkit/SKILL.md +214 -222
- package/.codex/skills/websocket-sse/SKILL.md +251 -172
- package/.codex/skills/workflow-engine/SKILL.md +178 -250
- package/.codex/skills/yunxiao-task-management/SKILL.md +489 -0
- package/.cursor/hooks/cursor-skill-eval.js +66 -6
- package/.cursor/hooks/stop.js +23 -1
- package/.cursor/skills/api-development/SKILL.md +179 -130
- package/.cursor/skills/architecture-design/SKILL.md +102 -212
- package/.cursor/skills/backend-annotations/SKILL.md +166 -220
- package/.cursor/skills/bug-detective/SKILL.md +225 -186
- package/.cursor/skills/code-patterns/SKILL.md +127 -244
- package/.cursor/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.cursor/skills/crud-development/SKILL.md +226 -307
- package/.cursor/skills/data-permission/SKILL.md +131 -202
- package/.cursor/skills/database-ops/SKILL.md +158 -355
- package/.cursor/skills/error-handler/SKILL.md +224 -285
- package/.cursor/skills/file-oss-management/SKILL.md +174 -169
- package/.cursor/skills/git-workflow/SKILL.md +123 -341
- package/.cursor/skills/json-serialization/SKILL.md +121 -137
- package/.cursor/skills/leniu-report-customization/SKILL.md +82 -2
- package/.cursor/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/.cursor/skills/loki-log-query/SKILL.md +400 -0
- package/.cursor/skills/loki-log-query/environments.json +45 -0
- package/.cursor/skills/mysql-debug/SKILL.md +58 -22
- package/.cursor/skills/performance-doctor/SKILL.md +83 -89
- package/.cursor/skills/redis-cache/SKILL.md +134 -185
- package/.cursor/skills/scheduled-jobs/SKILL.md +187 -224
- package/.cursor/skills/security-guard/SKILL.md +168 -276
- package/.cursor/skills/skill-creator/LICENSE.txt +202 -0
- package/.cursor/skills/skill-creator/SKILL.md +479 -0
- package/.cursor/skills/skill-creator/agents/analyzer.md +274 -0
- package/.cursor/skills/skill-creator/agents/comparator.md +202 -0
- package/.cursor/skills/skill-creator/agents/grader.md +223 -0
- package/.cursor/skills/skill-creator/assets/eval_review.html +146 -0
- package/.cursor/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.cursor/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.cursor/skills/skill-creator/references/schemas.md +430 -0
- package/.cursor/skills/skill-creator/scripts/__init__.py +0 -0
- package/.cursor/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.cursor/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.cursor/skills/skill-creator/scripts/improve_description.py +248 -0
- package/.cursor/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.cursor/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.cursor/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.cursor/skills/skill-creator/scripts/run_loop.py +332 -0
- package/.cursor/skills/skill-creator/scripts/utils.py +47 -0
- package/.cursor/skills/sms-mail/SKILL.md +266 -228
- package/.cursor/skills/social-login/SKILL.md +257 -195
- package/.cursor/skills/sync-back-merge/SKILL.md +66 -0
- package/.cursor/skills/tenant-management/SKILL.md +172 -188
- package/.cursor/skills/utils-toolkit/SKILL.md +214 -222
- package/.cursor/skills/websocket-sse/SKILL.md +251 -172
- package/.cursor/skills/workflow-engine/SKILL.md +178 -250
- package/.cursor/skills/yunxiao-task-management/SKILL.md +489 -0
- package/AGENTS.md +49 -540
- package/CLAUDE.md +73 -119
- package/README.md +37 -6
- package/bin/index.js +611 -25
- package/package.json +1 -1
- package/src/platform-map.json +4 -0
- package/src/skills/api-development/SKILL.md +179 -130
- package/src/skills/architecture-design/SKILL.md +102 -212
- package/src/skills/backend-annotations/SKILL.md +166 -220
- package/src/skills/bug-detective/SKILL.md +225 -186
- package/src/skills/code-patterns/SKILL.md +127 -244
- package/src/skills/codex-code-review/SKILL.md +261 -69
- package/src/skills/collaborating-with-codex/SKILL.md +96 -113
- package/src/skills/crud-development/SKILL.md +226 -307
- package/src/skills/data-permission/SKILL.md +131 -202
- package/src/skills/database-ops/SKILL.md +158 -355
- package/src/skills/error-handler/SKILL.md +224 -285
- package/src/skills/file-oss-management/SKILL.md +174 -169
- package/src/skills/git-workflow/SKILL.md +123 -341
- package/src/skills/json-serialization/SKILL.md +121 -137
- package/src/skills/leniu-report-customization/SKILL.md +82 -2
- package/src/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/src/skills/loki-log-query/SKILL.md +400 -0
- package/src/skills/loki-log-query/environments.json +45 -0
- package/src/skills/mysql-debug/SKILL.md +58 -22
- package/src/skills/performance-doctor/SKILL.md +83 -89
- package/src/skills/redis-cache/SKILL.md +134 -185
- package/src/skills/scheduled-jobs/SKILL.md +187 -224
- package/src/skills/security-guard/SKILL.md +168 -276
- package/src/skills/skill-creator/LICENSE.txt +202 -0
- package/src/skills/skill-creator/SKILL.md +479 -0
- package/src/skills/skill-creator/agents/analyzer.md +274 -0
- package/src/skills/skill-creator/agents/comparator.md +202 -0
- package/src/skills/skill-creator/agents/grader.md +223 -0
- package/src/skills/skill-creator/assets/eval_review.html +146 -0
- package/src/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/src/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/src/skills/skill-creator/references/schemas.md +430 -0
- package/src/skills/skill-creator/scripts/__init__.py +0 -0
- package/src/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/src/skills/skill-creator/scripts/generate_report.py +326 -0
- package/src/skills/skill-creator/scripts/improve_description.py +248 -0
- package/src/skills/skill-creator/scripts/package_skill.py +136 -0
- package/src/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/src/skills/skill-creator/scripts/run_eval.py +310 -0
- package/src/skills/skill-creator/scripts/run_loop.py +332 -0
- package/src/skills/skill-creator/scripts/utils.py +47 -0
- package/src/skills/sms-mail/SKILL.md +266 -228
- package/src/skills/social-login/SKILL.md +257 -195
- package/src/skills/sync-back-merge/SKILL.md +66 -0
- package/src/skills/tenant-management/SKILL.md +172 -188
- package/src/skills/utils-toolkit/SKILL.md +214 -222
- package/src/skills/websocket-sse/SKILL.md +251 -172
- package/src/skills/workflow-engine/SKILL.md +178 -250
- package/src/skills/yunxiao-task-management/SKILL.md +489 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: redis-cache
|
|
3
3
|
description: |
|
|
4
|
-
当需要使用Redis缓存、分布式锁、限流等功能时自动使用此Skill。包含
|
|
4
|
+
当需要使用Redis缓存、分布式锁、限流等功能时自动使用此Skill。包含 Redisson API、Spring Cache 注解使用规范、分布式锁实现、缓存key命名规范等。
|
|
5
5
|
|
|
6
6
|
触发场景:
|
|
7
7
|
- 使用Redis缓存数据
|
|
@@ -12,265 +12,245 @@ description: |
|
|
|
12
12
|
- 缓存key设计和命名
|
|
13
13
|
- 缓存清理和刷新
|
|
14
14
|
|
|
15
|
-
触发词:Redis、缓存、Cache、@Cacheable、@CacheEvict、@CachePut、
|
|
15
|
+
触发词:Redis、缓存、Cache、@Cacheable、@CacheEvict、@CachePut、Redisson、分布式锁、RLock、限流、RateLimiter、发布订阅、缓存key、缓存过期
|
|
16
16
|
|
|
17
17
|
核心警告:
|
|
18
18
|
- @Cacheable返回值不能使用不可变集合(List.of()、Set.of()、Map.of())
|
|
19
|
-
- 分布式锁必须在finally中释放,且需注入RedissonClient
|
|
20
|
-
- keys()和deleteKeys()会忽略租户隔离
|
|
19
|
+
- 分布式锁必须在finally中释放,且需注入RedissonClient
|
|
21
20
|
---
|
|
22
21
|
|
|
23
22
|
# Redis 缓存开发指南
|
|
24
23
|
|
|
25
|
-
> 模块位置:`ruoyi-common/ruoyi-common-redis`
|
|
26
|
-
|
|
27
24
|
## 快速索引
|
|
28
25
|
|
|
29
26
|
| 功能 | 工具类/注解 | 说明 |
|
|
30
27
|
|------|-------------|------|
|
|
31
|
-
| 对象缓存 | `RedisUtils
|
|
32
|
-
|
|
|
33
|
-
| Spring Cache | `CacheUtils.get/put/evict()` | Spring Cache 封装 |
|
|
34
|
-
| 缓存注解 | `@Cacheable/@CachePut/@CacheEvict` | 声明式缓存 |
|
|
28
|
+
| 对象缓存 | `RedissonClient` / `[你的RedisUtils]` | 基于 Redisson |
|
|
29
|
+
| Spring Cache | `@Cacheable/@CachePut/@CacheEvict` | 声明式缓存 |
|
|
35
30
|
| 分布式锁 | `redissonClient.getLock()` | 需注入 RedissonClient |
|
|
36
|
-
| 限流控制 | `
|
|
37
|
-
| 原子操作 | `
|
|
38
|
-
| 发布订阅 | `
|
|
31
|
+
| 限流控制 | Redisson `RRateLimiter` | 基于 Redisson |
|
|
32
|
+
| 原子操作 | Redisson `RAtomicLong` | 原子递增/递减 |
|
|
33
|
+
| 发布订阅 | Redisson `RTopic` | 消息通信 |
|
|
39
34
|
|
|
40
35
|
---
|
|
41
36
|
|
|
42
|
-
## 一、
|
|
43
|
-
|
|
44
|
-
```java
|
|
45
|
-
import org.dromara.common.redis.utils.RedisUtils;
|
|
46
|
-
```
|
|
37
|
+
## 一、Redisson 基础操作
|
|
47
38
|
|
|
48
39
|
### 1.1 基础缓存操作
|
|
49
40
|
|
|
50
41
|
```java
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
42
|
+
import org.redisson.api.RedissonClient;
|
|
43
|
+
import org.redisson.api.RBucket;
|
|
44
|
+
|
|
45
|
+
@Service
|
|
46
|
+
@RequiredArgsConstructor
|
|
47
|
+
public class CacheService {
|
|
48
|
+
|
|
49
|
+
private final RedissonClient redissonClient;
|
|
50
|
+
|
|
51
|
+
// 设置缓存
|
|
52
|
+
public void set(String key, Object value, Duration ttl) {
|
|
53
|
+
RBucket<Object> bucket = redissonClient.getBucket(key);
|
|
54
|
+
bucket.set(value, ttl);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 获取缓存
|
|
58
|
+
public <T> T get(String key) {
|
|
59
|
+
RBucket<T> bucket = redissonClient.getBucket(key);
|
|
60
|
+
return bucket.get();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 删除缓存
|
|
64
|
+
public boolean delete(String key) {
|
|
65
|
+
return redissonClient.getBucket(key).delete();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 判断是否存在
|
|
69
|
+
public boolean exists(String key) {
|
|
70
|
+
return redissonClient.getBucket(key).isExists();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 不存在时设置(原子操作)
|
|
74
|
+
public boolean setIfAbsent(String key, Object value, Duration ttl) {
|
|
75
|
+
RBucket<Object> bucket = redissonClient.getBucket(key);
|
|
76
|
+
return bucket.trySet(value, ttl);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
63
79
|
```
|
|
64
80
|
|
|
65
81
|
### 1.2 集合操作
|
|
66
82
|
|
|
67
83
|
```java
|
|
68
84
|
// List
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
List<String> result =
|
|
72
|
-
List<String> range = RedisUtils.getCacheListRange("myList", 0, 10);
|
|
85
|
+
RList<String> list = redissonClient.getList("myList");
|
|
86
|
+
list.addAll(dataList);
|
|
87
|
+
List<String> result = list.readAll();
|
|
73
88
|
|
|
74
89
|
// Set
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Set<String> result =
|
|
90
|
+
RSet<String> set = redissonClient.getSet("mySet");
|
|
91
|
+
set.addAll(dataSet);
|
|
92
|
+
Set<String> result = set.readAll();
|
|
78
93
|
|
|
79
94
|
// Map
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
Set<String> keys = RedisUtils.getCacheMapKeySet("myMap");
|
|
85
|
-
RedisUtils.delCacheMapValue("myMap", "key1");
|
|
86
|
-
RedisUtils.delMultiCacheMapValue("myMap", new HashSet<>(Arrays.asList("key1", "key2")));
|
|
87
|
-
Map<String, Object> values = RedisUtils.getMultiCacheMapValue("myMap", keySet);
|
|
95
|
+
RMap<String, Object> map = redissonClient.getMap("myMap");
|
|
96
|
+
map.putAll(dataMap);
|
|
97
|
+
map.put("key3", "value3");
|
|
98
|
+
Object value = map.get("key1");
|
|
88
99
|
```
|
|
89
100
|
|
|
90
101
|
### 1.3 发布订阅
|
|
91
102
|
|
|
92
103
|
```java
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
// 发布消息
|
|
105
|
+
RTopic topic = redissonClient.getTopic("notification:channel");
|
|
106
|
+
topic.publish(messageObj);
|
|
107
|
+
|
|
108
|
+
// 订阅消息
|
|
109
|
+
RTopic topic = redissonClient.getTopic("notification:channel");
|
|
110
|
+
topic.addListener(MessageDTO.class, (channel, msg) -> {
|
|
111
|
+
// 处理消息
|
|
112
|
+
});
|
|
96
113
|
```
|
|
97
114
|
|
|
98
115
|
### 1.4 限流控制
|
|
99
116
|
|
|
100
117
|
```java
|
|
118
|
+
import org.redisson.api.RRateLimiter;
|
|
101
119
|
import org.redisson.api.RateType;
|
|
120
|
+
import org.redisson.api.RateIntervalUnit;
|
|
102
121
|
|
|
122
|
+
RRateLimiter limiter = redissonClient.getRateLimiter("api:limit:user:" + userId);
|
|
103
123
|
// 每10秒最多100个请求
|
|
104
|
-
|
|
105
|
-
if (remaining == -1) {
|
|
106
|
-
throw new ServiceException("请求过于频繁");
|
|
107
|
-
}
|
|
124
|
+
limiter.trySetRate(RateType.OVERALL, 100, 10, RateIntervalUnit.SECONDS);
|
|
108
125
|
|
|
109
|
-
|
|
110
|
-
|
|
126
|
+
if (!limiter.tryAcquire()) {
|
|
127
|
+
throw new [你的异常类]("请求过于频繁");
|
|
128
|
+
}
|
|
111
129
|
```
|
|
112
130
|
|
|
113
131
|
### 1.5 原子操作
|
|
114
132
|
|
|
115
133
|
```java
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
long
|
|
119
|
-
long newVal =
|
|
134
|
+
RAtomicLong counter = redissonClient.getAtomicLong("counter:view");
|
|
135
|
+
counter.set(0L);
|
|
136
|
+
long value = counter.get();
|
|
137
|
+
long newVal = counter.incrementAndGet();
|
|
138
|
+
long newVal = counter.decrementAndGet();
|
|
120
139
|
```
|
|
121
140
|
|
|
122
|
-
|
|
141
|
+
---
|
|
123
142
|
|
|
124
|
-
|
|
125
|
-
// ⚠️ keys() 和 deleteKeys() 会忽略租户隔离
|
|
126
|
-
Collection<String> keys = RedisUtils.keys("user:*");
|
|
143
|
+
## 二、Spring Cache 注解使用规范
|
|
127
144
|
|
|
128
|
-
|
|
129
|
-
Collection<String> keys = RedisUtils.keys(options);
|
|
145
|
+
### @Cacheable - 查询缓存
|
|
130
146
|
|
|
131
|
-
|
|
132
|
-
|
|
147
|
+
```java
|
|
148
|
+
@Cacheable(value = "dictData", key = "#dictType")
|
|
149
|
+
@Override
|
|
150
|
+
public List<DictDataVo> listDictDataByType(String dictType) {
|
|
151
|
+
if (dictType == null || dictType.isBlank()) {
|
|
152
|
+
return Collections.emptyList();
|
|
153
|
+
}
|
|
154
|
+
List<DictData> dictDataList = dictDataMapper.selectByType(dictType);
|
|
155
|
+
if (dictDataList.isEmpty()) {
|
|
156
|
+
return Collections.emptyList(); // 返回空列表防止缓存穿透
|
|
157
|
+
}
|
|
158
|
+
return dictDataList.stream()
|
|
159
|
+
.map(d -> BeanUtil.copyProperties(d, DictDataVo.class))
|
|
160
|
+
.toList();
|
|
161
|
+
}
|
|
133
162
|
```
|
|
134
163
|
|
|
135
|
-
###
|
|
164
|
+
### @CachePut / @CacheEvict
|
|
165
|
+
|
|
166
|
+
```java
|
|
167
|
+
@CachePut(value = "dictData", key = "#bo.dictType")
|
|
168
|
+
public List<DictDataVo> insertDictType(DictTypeBo bo) { ... }
|
|
136
169
|
|
|
137
|
-
|
|
170
|
+
@CacheEvict(value = "dictData", key = "#dictType")
|
|
171
|
+
public void deleteDictType(String dictType) { ... }
|
|
138
172
|
|
|
139
|
-
|
|
173
|
+
@CacheEvict(value = "dictData", allEntries = true)
|
|
174
|
+
public void clearAllDictCache() { ... }
|
|
175
|
+
```
|
|
140
176
|
|
|
141
|
-
|
|
177
|
+
### 返回值禁止使用不可变集合
|
|
142
178
|
|
|
143
179
|
```java
|
|
144
|
-
|
|
180
|
+
// ❌ 禁止! @Cacheable 返回值序列化失败
|
|
181
|
+
return List.of(data1, data2);
|
|
182
|
+
return Set.of("admin", "user");
|
|
183
|
+
return Map.of("key1", "value1");
|
|
145
184
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
185
|
+
// ✅ 正确:使用可变集合
|
|
186
|
+
List<DictDataVo> result = new ArrayList<>();
|
|
187
|
+
result.add(data1);
|
|
188
|
+
return result;
|
|
150
189
|
```
|
|
151
190
|
|
|
152
191
|
---
|
|
153
192
|
|
|
154
|
-
## 三、CacheNames
|
|
193
|
+
## 三、CacheNames 命名规范
|
|
155
194
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
### 命名格式
|
|
195
|
+
### 推荐格式
|
|
159
196
|
|
|
160
197
|
```
|
|
161
|
-
cacheNames#ttl#maxIdleTime#maxSize
|
|
198
|
+
cacheNames#ttl#maxIdleTime#maxSize
|
|
162
199
|
- ttl: 过期时间(0=不过期,默认0)
|
|
163
200
|
- maxIdleTime: 最大空闲时间(0=不检测,默认0)
|
|
164
201
|
- maxSize: 最大条数(0=无限,默认0)
|
|
165
|
-
- local: 本地缓存(1开启,0关闭,默认1)
|
|
166
202
|
```
|
|
167
203
|
|
|
168
204
|
```java
|
|
169
205
|
"test#60s" // 60秒过期
|
|
170
206
|
"test#0#60s" // 不过期,60秒空闲清理
|
|
171
207
|
"test#0#1m#1000" // 不过期,1分钟空闲,最大1000条
|
|
172
|
-
"test#1h#0#500
|
|
208
|
+
"test#1h#0#500" // 1小时过期,最大500条
|
|
173
209
|
```
|
|
174
210
|
|
|
175
|
-
###
|
|
211
|
+
### 常量定义示例
|
|
176
212
|
|
|
177
213
|
```java
|
|
178
214
|
public interface CacheNames {
|
|
179
|
-
String DEMO_CACHE = "demo:cache#60s#10m#20";
|
|
180
215
|
String SYS_CONFIG = "sys_config";
|
|
181
216
|
String SYS_DICT = "sys_dict";
|
|
182
|
-
String SYS_DICT_TYPE = "sys_dict_type";
|
|
183
|
-
String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d";
|
|
184
|
-
String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d";
|
|
185
217
|
String SYS_USER_NAME = "sys_user_name#30d";
|
|
186
|
-
String SYS_NICKNAME = "sys_nickname#30d";
|
|
187
218
|
String SYS_DEPT = "sys_dept#30d";
|
|
188
|
-
String SYS_OSS = "sys_oss#30d";
|
|
189
|
-
String SYS_ROLE_CUSTOM = "sys_role_custom#30d";
|
|
190
|
-
String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d";
|
|
191
|
-
String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
|
|
192
|
-
String ONLINE_TOKEN = "online_tokens";
|
|
193
219
|
}
|
|
194
220
|
```
|
|
195
221
|
|
|
196
222
|
---
|
|
197
223
|
|
|
198
|
-
##
|
|
224
|
+
## 四、分布式锁
|
|
199
225
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
```java
|
|
203
|
-
@Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
|
|
204
|
-
@Override
|
|
205
|
-
public List<SysDictDataVo> listDictDataByType(String dictType) {
|
|
206
|
-
if (StringUtils.isBlank(dictType)) {
|
|
207
|
-
return Collections.emptyList();
|
|
208
|
-
}
|
|
209
|
-
List<SysDictData> dictDataList = dictDataMapper.selectByType(dictType);
|
|
210
|
-
if (CollUtil.isEmpty(dictDataList)) {
|
|
211
|
-
return Collections.emptyList(); // 返回空列表防止缓存穿透
|
|
212
|
-
}
|
|
213
|
-
return MapstructUtils.convert(dictDataList, SysDictDataVo.class);
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### @CachePut / @CacheEvict
|
|
218
|
-
|
|
219
|
-
```java
|
|
220
|
-
@CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
|
|
221
|
-
public List<SysDictDataVo> insertDictType(SysDictTypeBo bo) { ... }
|
|
222
|
-
|
|
223
|
-
@CacheEvict(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
|
|
224
|
-
public void deleteDictType(String dictType) { ... }
|
|
225
|
-
|
|
226
|
-
@CacheEvict(cacheNames = CacheNames.SYS_DICT, allEntries = true)
|
|
227
|
-
public void clearAllDictCache() { ... }
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### 返回值禁止使用不可变集合
|
|
231
|
-
|
|
232
|
-
```java
|
|
233
|
-
// ❌ 禁止!@Cacheable 返回值序列化失败
|
|
234
|
-
return List.of(data1, data2);
|
|
235
|
-
return Set.of("admin", "user");
|
|
236
|
-
return Map.of("key1", "value1");
|
|
237
|
-
|
|
238
|
-
// ✅ 正确:使用可变集合
|
|
239
|
-
List<SysDictDataVo> result = new ArrayList<>();
|
|
240
|
-
result.add(data1);
|
|
241
|
-
return result;
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## 五、分布式锁
|
|
247
|
-
|
|
248
|
-
> RedisUtils **不提供** `getLock()`,需直接注入 `RedissonClient`。
|
|
226
|
+
> 直接注入 `RedissonClient` 使用。
|
|
249
227
|
|
|
250
228
|
```java
|
|
251
229
|
@Service
|
|
252
230
|
@RequiredArgsConstructor
|
|
253
|
-
public class OrderServiceImpl
|
|
231
|
+
public class OrderServiceImpl {
|
|
254
232
|
|
|
255
233
|
private final RedissonClient redissonClient;
|
|
256
234
|
|
|
257
235
|
public void submitOrder(OrderBo orderBo) {
|
|
258
|
-
String lockKey = "lock:submit:order:" +
|
|
236
|
+
String lockKey = "lock:submit:order:" + orderBo.getUserId();
|
|
259
237
|
RLock lock = redissonClient.getLock(lockKey);
|
|
260
238
|
|
|
261
239
|
try {
|
|
262
240
|
boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
|
|
263
241
|
if (!locked) {
|
|
264
|
-
throw new
|
|
242
|
+
throw new [你的异常类]("请勿重复提交订单");
|
|
265
243
|
}
|
|
266
244
|
try {
|
|
267
245
|
orderMapper.insert(orderBo);
|
|
268
246
|
} finally {
|
|
269
|
-
lock.
|
|
247
|
+
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
|
|
248
|
+
lock.unlock(); // 必须在 finally 中释放
|
|
249
|
+
}
|
|
270
250
|
}
|
|
271
251
|
} catch (InterruptedException e) {
|
|
272
252
|
Thread.currentThread().interrupt();
|
|
273
|
-
throw new
|
|
253
|
+
throw new [你的异常类]("订单提交被中断");
|
|
274
254
|
}
|
|
275
255
|
}
|
|
276
256
|
}
|
|
@@ -278,7 +258,7 @@ public class OrderServiceImpl implements IOrderService {
|
|
|
278
258
|
|
|
279
259
|
---
|
|
280
260
|
|
|
281
|
-
##
|
|
261
|
+
## 五、缓存 Key 命名规范
|
|
282
262
|
|
|
283
263
|
```
|
|
284
264
|
格式:{业务模块}:{功能}:{具体标识}
|
|
@@ -292,42 +272,11 @@ limit:api:user:123 limit:sms:18888888888
|
|
|
292
272
|
|
|
293
273
|
---
|
|
294
274
|
|
|
295
|
-
##
|
|
296
|
-
|
|
297
|
-
```java
|
|
298
|
-
// ⚠️ keys() 和 deleteKeys() 会忽略租户隔离,需手动拼接
|
|
299
|
-
String tenantId = LoginHelper.getTenantId();
|
|
300
|
-
Collection<String> keys = RedisUtils.keys(tenantId + ":user:*");
|
|
301
|
-
|
|
302
|
-
// CacheUtils 会自动处理租户隔离
|
|
303
|
-
CacheUtils.clear(CacheNames.SYS_USER_NAME);
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
## 八、注意事项速查
|
|
275
|
+
## 六、注意事项速查
|
|
309
276
|
|
|
310
277
|
1. **@Cacheable 返回值不能使用不可变集合**(List.of()、Set.of()、Map.of())
|
|
311
278
|
2. **分布式锁必须在 finally 中释放**
|
|
312
|
-
3.
|
|
313
|
-
4.
|
|
314
|
-
5.
|
|
315
|
-
6.
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
## 九、核心文件位置
|
|
320
|
-
|
|
321
|
-
| 文件 | 位置 |
|
|
322
|
-
|------|------|
|
|
323
|
-
| RedisUtils | `ruoyi-common/ruoyi-common-redis/.../utils/RedisUtils.java` |
|
|
324
|
-
| CacheUtils | `ruoyi-common/ruoyi-common-redis/.../utils/CacheUtils.java` |
|
|
325
|
-
| CacheNames | `ruoyi-common/ruoyi-common-core/.../constant/CacheNames.java` |
|
|
326
|
-
| GlobalConstants | `ruoyi-common/ruoyi-common-core/.../constant/GlobalConstants.java` |
|
|
327
|
-
|
|
328
|
-
---
|
|
329
|
-
|
|
330
|
-
## 多项目适配说明
|
|
331
|
-
|
|
332
|
-
- 如果需要 leniu-tengyun-core 项目的 Redis 开发规范,请使用 `leniu-redis-cache` skill
|
|
333
|
-
- leniu-tengyun-core 的 RedisUtil 工具类方法名与 RuoYi-Vue-Plus 的 RedisUtils 不同
|
|
279
|
+
3. **返回空列表而不是 null**,防止缓存穿透
|
|
280
|
+
4. **设置随机过期时间偏移**,避免缓存雪崩
|
|
281
|
+
5. **热点数据用分布式锁 + 双重检查**,防止缓存击穿
|
|
282
|
+
6. **keys() 模式匹配要谨慎**,生产环境避免大范围扫描
|