@llryiop/avatar-boot-cli 1.0.0 → 1.0.2

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.
Files changed (72) hide show
  1. package/docs/exam-question-generate-api.md +163 -0
  2. package/package.json +1 -1
  3. package/src/prompts.js +3 -3
  4. package/src/transform.js +1 -1
  5. package/templates/.claude/skills/avatar-boot-starter-feign/README.md +243 -0
  6. package/templates/.claude/skills/avatar-boot-starter-feign/SKILL.md +47 -219
  7. package/templates/.claude/skills/avatar-boot-starter-feign/references//345/212/237/350/203/275/350/257/246/350/247/243.md +65 -0
  8. package/templates/.claude/skills/avatar-boot-starter-feign/references//345/277/253/351/200/237/346/216/245/345/205/245/346/214/207/345/215/227.md +75 -0
  9. package/templates/.claude/skills/avatar-boot-starter-feign/references//351/205/215/347/275/256/345/217/202/350/200/203.md +70 -0
  10. package/templates/.claude/skills/avatar-boot-starter-job/README.md +437 -0
  11. package/templates/.claude/skills/avatar-boot-starter-job/SKILL.md +35 -414
  12. package/templates/.claude/skills/avatar-boot-starter-job/references//345/270/270/350/247/201/351/227/256/351/242/230.md +55 -0
  13. package/templates/.claude/skills/avatar-boot-starter-job/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +124 -0
  14. package/templates/.claude/skills/avatar-boot-starter-job/references//347/233/221/346/216/247/346/214/207/346/240/207.md +72 -0
  15. package/templates/.claude/skills/avatar-boot-starter-kafka/README.md +580 -0
  16. package/templates/.claude/skills/avatar-boot-starter-kafka/SKILL.md +36 -560
  17. package/templates/.claude/skills/avatar-boot-starter-kafka/references//346/234/200/344/275/263/345/256/236/350/267/265.md +43 -0
  18. package/templates/.claude/skills/avatar-boot-starter-kafka/references//346/240/270/345/277/203/345/212/237/350/203/275.md +117 -0
  19. package/templates/.claude/skills/avatar-boot-starter-kafka/references//351/205/215/347/275/256/345/217/202/350/200/203.md +54 -0
  20. package/templates/.claude/skills/avatar-boot-starter-mysql/README.md +572 -0
  21. package/templates/.claude/skills/avatar-boot-starter-mysql/SKILL.md +40 -550
  22. package/templates/.claude/skills/avatar-boot-starter-mysql/references//345/256/236/344/275/223/344/270/216/345/212/237/350/203/275.md +96 -0
  23. package/templates/.claude/skills/avatar-boot-starter-mysql/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/346/225/260/346/215/256/346/272/220.md +91 -0
  24. package/templates/.claude/skills/avatar-boot-starter-mysql/references//351/253/230/347/272/247/347/211/271/346/200/247/344/270/216/351/205/215/347/275/256.md +59 -0
  25. package/templates/.claude/skills/avatar-boot-starter-nacos/README.md +901 -0
  26. package/templates/.claude/skills/avatar-boot-starter-nacos/SKILL.md +40 -879
  27. package/templates/.claude/skills/avatar-boot-starter-nacos/references//345/212/237/350/203/275/344/275/277/347/224/250.md +134 -0
  28. package/templates/.claude/skills/avatar-boot-starter-nacos/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +96 -0
  29. package/templates/.claude/skills/avatar-boot-starter-nacos/references//346/225/205/351/232/234/346/216/222/346/237/245.md +64 -0
  30. package/templates/.claude/skills/avatar-boot-starter-oss/README.md +594 -0
  31. package/templates/.claude/skills/avatar-boot-starter-oss/SKILL.md +52 -570
  32. package/templates/.claude/skills/avatar-boot-starter-oss/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +77 -0
  33. package/templates/.claude/skills/avatar-boot-starter-oss/references//346/240/270/345/277/203/345/212/237/350/203/275.md +94 -0
  34. package/templates/.claude/skills/avatar-boot-starter-oss/references//350/247/204/350/214/203/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.md +61 -0
  35. package/templates/.claude/skills/avatar-boot-starter-redis/README.md +586 -0
  36. package/templates/.claude/skills/avatar-boot-starter-redis/SKILL.md +42 -566
  37. package/templates/.claude/skills/avatar-boot-starter-redis/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +78 -0
  38. package/templates/.claude/skills/avatar-boot-starter-redis/references//346/225/260/346/215/256/346/223/215/344/275/234.md +111 -0
  39. package/templates/.claude/skills/avatar-boot-starter-redis/references//351/253/230/347/272/247/345/212/237/350/203/275.md +90 -0
  40. package/templates/.claude/skills/avatar-boot-starter-rocketmq/README.md +662 -0
  41. package/templates/.claude/skills/avatar-boot-starter-rocketmq/SKILL.md +48 -640
  42. package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//346/240/270/345/277/203/345/212/237/350/203/275.md +101 -0
  43. package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//351/205/215/347/275/256/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.md +44 -0
  44. package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//351/253/230/347/272/247/347/211/271/346/200/247.md +71 -0
  45. package/templates/.claude/skills/avatar-boot-starter-web/README.md +1007 -0
  46. package/templates/.claude/skills/avatar-boot-starter-web/SKILL.md +150 -1003
  47. package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-LogInfo/346/263/250/350/247/243.md +75 -0
  48. package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/345/205/250/345/261/200/345/274/202/345/270/270/345/244/204/347/220/206.md +90 -0
  49. package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/346/214/207/346/240/207/347/233/221/346/216/247.md +74 -0
  50. package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/346/227/245/345/277/227/344/275/223/347/263/273.md +73 -0
  51. package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/350/257/267/346/261/202/344/270/212/344/270/213/346/226/207.md +77 -0
  52. package/templates/.claude/skills/avatar-boot-starter-web/references//345/277/253/351/200/237/346/216/245/345/205/245/346/214/207/345/215/227.md +52 -0
  53. package/templates/.claude/skills/avatar-boot-starter-web/references//346/263/250/346/204/217/344/272/213/351/241/271.md +68 -0
  54. package/templates/.claude/skills/avatar-boot-starter-web/references//350/207/252/345/256/232/344/271/211/346/211/251/345/261/225/346/214/207/345/215/227.md +107 -0
  55. package/templates/.claude/skills/avatar-boot-starter-web/references//351/205/215/347/275/256/345/217/202/350/200/203.md +107 -0
  56. package/templates/.claude/skills/crud-generator/SKILL.md +133 -64
  57. package/templates/.claude/skills/database-design/README.md +207 -0
  58. package/templates/.claude/skills/database-design/SKILL.md +469 -82
  59. package/templates/.claude/skills/database-design/references//345/221/275/345/220/215/350/247/204/350/214/203.md +232 -0
  60. package/templates/.claude/skills/database-design/references//345/255/227/346/256/265/347/261/273/345/236/213/350/247/204/350/214/203.md +400 -0
  61. package/templates/.claude/skills/database-design/references//347/264/242/345/274/225/350/247/204/350/214/203.md +506 -0
  62. package/templates/README.md +65 -100
  63. package/templates/avatar-scaffold-api/pom.xml +0 -5
  64. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/api/LoginFeignClient.java +2 -0
  65. package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/exception/LoginErrorCode.java +25 -0
  66. package/templates/avatar-scaffold-service/pom.xml +25 -87
  67. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/feign/DemoFeign.java +4 -1
  68. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/UserLoginRepository.java +10 -0
  69. package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/mapper/UserLoginMapper.java +4 -1
  70. package/templates/avatar-scaffold-service/src/main/resources/application-dev.yaml +3 -5
  71. package/templates/avatar-scaffold-service/src/main/resources/application-local.yaml +21 -21
  72. package/templates/pom.xml +9 -18
@@ -1,586 +1,62 @@
1
1
  ---
2
2
  name: avatar-boot-starter-redis
3
- description: 当涉及 Redis、缓存、Redisson、分布式锁 相关功能时使用此技能 - 为 Spring Boot 3.5.3 应用提供基于 Redisson 3.40.2 Redis 缓存与分布式锁能力,包含自动配置、连接池管理、Spring Cache 集成。
3
+ description: Avatar Boot Redis 模块使用指南。当用户询问 Redis 缓存操作、分布式锁、限流器、布隆过滤器、String/Hash/Set/ZSet 数据结构操作,或需要接入 avatar-boot-starter-redis 时触发。
4
4
  ---
5
5
 
6
- Avatar Boot Redis 集成模块,基于 Redisson 3.40.2 提供开箱即用的缓存、分布式锁和数据结构操作能力。
6
+ # Avatar Boot Starter Redis 使用指南
7
7
 
8
- ## 功能特性
8
+ 你是 Avatar Boot Redis 模块的使用顾问与开发助手。
9
9
 
10
- - ✅ **自动配置** - 基于 Spring Boot 自动配置机制,自动装配 RedisTemplate 和 Redisson 客户端
11
- - ✅ **Redisson 集成** - 内置 Redisson 3.40.2,提供分布式锁、信号量等高级功能
12
- - ✅ **Spring Cache 支持** - 无缝集成 Spring Cache 抽象,支持 @Cacheable、@CacheEvict、@CachePut
13
- - ✅ **连接池管理** - 基于 Lettuce 连接池,支持高并发场景
14
- - ✅ **序列化可配置** - 支持多种序列化方式,推荐 Jackson2JsonRedisSerializer
15
- - ✅ **完善的监控** - 集成 Micrometer 指标,便于监控 Redis 连接状态
10
+ ## 交互流程(必须遵守)
16
11
 
17
- ## 快速开始
12
+ **每次被触发时,先通过 AskUserQuestion 工具询问用户意图:**
18
13
 
19
- ### 1. 添加依赖
14
+ 问题:"您好!我是 Avatar Boot Redis 模块助手,请问您需要哪方面的帮助?"
15
+ 选项:
16
+ 1. **快速接入** - 添加依赖、@EnableRedis、配置连接
17
+ 2. **数据结构操作** - String/Hash/Set/ZSet 操作示例
18
+ 3. **缓存操作** - RedisCacheClient 使用、批量删除
19
+ 4. **分布式锁** - RedissonLockClient 加锁/解锁
20
+ 5. **限流与布隆过滤器** - 令牌桶/滑动窗口限流、布隆过滤器去重
20
21
 
21
- 在项目的 `pom.xml` 中添加依赖:
22
+ **根据用户选择,用 Read 工具按下方「文档读取路由」加载对应文档,然后给出具体指导。**
22
23
 
23
- ```xml
24
- <dependency>
25
- <groupId>com.iflytek.avatar.boot</groupId>
26
- <artifactId>avatar-boot-starter-redis</artifactId>
27
- </dependency>
28
- ```
29
-
30
- > 版本由 Avatar Boot BOM 统一管理,无需指定 version。
31
-
32
- ### 2. 配置文件
33
-
34
- 在 `application.yml` 中添加 Redis 连接配置:
35
-
36
- ```yaml
37
- spring:
38
- data:
39
- redis:
40
- host: localhost
41
- port: 6379
42
- password: your-password # 无密码可省略
43
- database: 0
44
- timeout: 3000ms
45
- lettuce:
46
- pool:
47
- max-active: 16 # 最大连接数(默认 8)
48
- max-idle: 8 # 最大空闲连接数(默认 8)
49
- min-idle: 2 # 最小空闲连接数(默认 0)
50
- max-wait: 3000ms # 获取连接最大等待时间
51
- ```
52
-
53
- ### 3. 基本使用
54
-
55
- 注入 `StringRedisTemplate` 或 `RedisTemplate` 即可操作 Redis:
56
-
57
- ```java
58
- package com.example.service;
59
-
60
- import lombok.RequiredArgsConstructor;
61
- import lombok.extern.slf4j.Slf4j;
62
- import org.springframework.data.redis.core.StringRedisTemplate;
63
- import org.springframework.stereotype.Service;
64
-
65
- import java.util.concurrent.TimeUnit;
66
-
67
- @Slf4j
68
- @Service
69
- @RequiredArgsConstructor
70
- public class CacheService {
71
-
72
- private final StringRedisTemplate stringRedisTemplate;
73
-
74
- /**
75
- * 设置缓存(必须设置过期时间)
76
- */
77
- public void setCache(String key, String value, long timeout, TimeUnit unit) {
78
- stringRedisTemplate.opsForValue().set(key, value, timeout, unit);
79
- }
80
-
81
- /**
82
- * 获取缓存
83
- */
84
- public String getCache(String key) {
85
- return stringRedisTemplate.opsForValue().get(key);
86
- }
87
-
88
- /**
89
- * 删除缓存
90
- */
91
- public Boolean deleteCache(String key) {
92
- return stringRedisTemplate.delete(key);
93
- }
94
- }
95
- ```
96
-
97
- ## Redisson 配置
98
-
99
- ### 单节点模式
100
-
101
- 通过 `application.yml` 配置 Redisson:
102
-
103
- ```yaml
104
- spring:
105
- data:
106
- redis:
107
- host: localhost
108
- port: 6379
109
- password: your-password
110
- redisson:
111
- config: |
112
- singleServerConfig:
113
- address: "redis://localhost:6379"
114
- password: "your-password"
115
- connectionMinimumIdleSize: 4
116
- connectionPoolSize: 16
117
- idleConnectionTimeout: 10000
118
- connectTimeout: 10000
119
- timeout: 3000
120
- retryAttempts: 3
121
- retryInterval: 1500
122
- ```
123
-
124
- ### 集群模式
125
-
126
- ```yaml
127
- spring:
128
- data:
129
- redis:
130
- redisson:
131
- config: |
132
- clusterServersConfig:
133
- nodeAddresses:
134
- - "redis://node1:6379"
135
- - "redis://node2:6379"
136
- - "redis://node3:6379"
137
- password: "your-password"
138
- masterConnectionMinimumIdleSize: 4
139
- masterConnectionPoolSize: 16
140
- slaveConnectionMinimumIdleSize: 4
141
- slaveConnectionPoolSize: 16
142
- ```
143
-
144
- 也可以通过独立的 `redisson.yaml` 文件配置:
145
-
146
- ```yaml
147
- # resources/redisson.yaml
148
- singleServerConfig:
149
- address: "redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}"
150
- password: "${REDIS_PASSWORD:}"
151
- connectionMinimumIdleSize: 4
152
- connectionPoolSize: 16
153
- ```
154
-
155
- 然后在 `application.yml` 中引用:
156
-
157
- ```yaml
158
- spring:
159
- data:
160
- redis:
161
- redisson:
162
- file: classpath:redisson.yaml
163
- ```
164
-
165
- ## RedisTemplate 使用示例
166
-
167
- ### 自定义 RedisTemplate 序列化
168
-
169
- ```java
170
- package com.example.config;
171
-
172
- import com.fasterxml.jackson.annotation.JsonAutoDetect;
173
- import com.fasterxml.jackson.annotation.PropertyAccessor;
174
- import com.fasterxml.jackson.databind.ObjectMapper;
175
- import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
176
- import org.springframework.context.annotation.Bean;
177
- import org.springframework.context.annotation.Configuration;
178
- import org.springframework.data.redis.connection.RedisConnectionFactory;
179
- import org.springframework.data.redis.core.RedisTemplate;
180
- import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
181
- import org.springframework.data.redis.serializer.StringRedisSerializer;
182
-
183
- @Configuration
184
- public class RedisConfig {
185
-
186
- @Bean
187
- public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
188
- RedisTemplate<String, Object> template = new RedisTemplate<>();
189
- template.setConnectionFactory(factory);
190
-
191
- // Key 使用 String 序列化
192
- StringRedisSerializer stringSerializer = new StringRedisSerializer();
193
- template.setKeySerializer(stringSerializer);
194
- template.setHashKeySerializer(stringSerializer);
195
-
196
- // Value 使用 Jackson 序列化
197
- ObjectMapper om = new ObjectMapper();
198
- om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
199
- om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
200
- ObjectMapper.DefaultTyping.NON_FINAL);
201
- Jackson2JsonRedisSerializer<Object> jacksonSerializer =
202
- new Jackson2JsonRedisSerializer<>(om, Object.class);
203
-
204
- template.setValueSerializer(jacksonSerializer);
205
- template.setHashValueSerializer(jacksonSerializer);
206
- template.afterPropertiesSet();
207
- return template;
208
- }
209
- }
210
- ```
211
-
212
- ### 操作各种数据结构
213
-
214
- ```java
215
- @Service
216
- @RequiredArgsConstructor
217
- public class RedisDataService {
218
-
219
- private final RedisTemplate<String, Object> redisTemplate;
220
-
221
- // String 操作
222
- public void stringOps() {
223
- redisTemplate.opsForValue().set("avatar:user:123", userObj, 30, TimeUnit.MINUTES);
224
- Object user = redisTemplate.opsForValue().get("avatar:user:123");
225
- }
226
-
227
- // Hash 操作
228
- public void hashOps() {
229
- redisTemplate.opsForHash().put("avatar:user:profile:123", "name", "张三");
230
- redisTemplate.opsForHash().put("avatar:user:profile:123", "age", 25);
231
- Object name = redisTemplate.opsForHash().get("avatar:user:profile:123", "name");
232
- }
233
-
234
- // List 操作
235
- public void listOps() {
236
- redisTemplate.opsForList().rightPush("avatar:queue:tasks", task);
237
- Object task = redisTemplate.opsForList().leftPop("avatar:queue:tasks");
238
- }
239
-
240
- // Set 操作
241
- public void setOps() {
242
- redisTemplate.opsForSet().add("avatar:user:tags:123", "vip", "active");
243
- Boolean isMember = redisTemplate.opsForSet().isMember("avatar:user:tags:123", "vip");
244
- }
245
-
246
- // ZSet(有序集合)操作
247
- public void zsetOps() {
248
- redisTemplate.opsForZSet().add("avatar:rank:score", "user1", 100.0);
249
- Set<Object> top10 = redisTemplate.opsForZSet().reverseRange("avatar:rank:score", 0, 9);
250
- }
251
- }
252
- ```
253
-
254
- ## 分布式锁(Redisson)
255
-
256
- ### 基本锁使用
257
-
258
- ```java
259
- package com.example.service;
260
-
261
- import lombok.RequiredArgsConstructor;
262
- import lombok.extern.slf4j.Slf4j;
263
- import org.redisson.api.RLock;
264
- import org.redisson.api.RedissonClient;
265
- import org.springframework.stereotype.Service;
266
-
267
- import java.util.concurrent.TimeUnit;
268
-
269
- @Slf4j
270
- @Service
271
- @RequiredArgsConstructor
272
- public class DistributedLockService {
273
-
274
- private final RedissonClient redissonClient;
275
-
276
- /**
277
- * 使用分布式锁保护临界区
278
- */
279
- public void executeWithLock(String bizKey, Runnable task) {
280
- RLock lock = redissonClient.getLock("avatar:lock:" + bizKey);
281
- boolean acquired = false;
282
- try {
283
- // 尝试获取锁:等待 5 秒,持有锁 30 秒后自动释放
284
- acquired = lock.tryLock(5, 30, TimeUnit.SECONDS);
285
- if (acquired) {
286
- log.info("获取锁成功: {}", bizKey);
287
- task.run();
288
- } else {
289
- log.warn("获取锁失败: {}", bizKey);
290
- throw new RuntimeException("获取分布式锁超时");
291
- }
292
- } catch (InterruptedException e) {
293
- Thread.currentThread().interrupt();
294
- throw new RuntimeException("获取锁被中断", e);
295
- } finally {
296
- if (acquired && lock.isHeldByCurrentThread()) {
297
- lock.unlock();
298
- log.info("释放锁: {}", bizKey);
299
- }
300
- }
301
- }
302
-
303
- /**
304
- * 使用看门狗机制(自动续期)
305
- * 不指定 leaseTime 时,Redisson 默认启动看门狗,每 10 秒续期一次
306
- */
307
- public void executeWithWatchdog(String bizKey, Runnable task) {
308
- RLock lock = redissonClient.getLock("avatar:lock:" + bizKey);
309
- lock.lock(); // 看门狗自动续期
310
- try {
311
- task.run();
312
- } finally {
313
- if (lock.isHeldByCurrentThread()) {
314
- lock.unlock();
315
- }
316
- }
317
- }
318
- }
319
- ```
320
-
321
- ### 高级锁类型
322
-
323
- ```java
324
- @Service
325
- @RequiredArgsConstructor
326
- public class AdvancedLockService {
327
-
328
- private final RedissonClient redissonClient;
329
-
330
- /**
331
- * 公平锁 - 按请求顺序获取锁
332
- */
333
- public void fairLock(String bizKey) {
334
- RLock fairLock = redissonClient.getFairLock("avatar:fairlock:" + bizKey);
335
- fairLock.lock();
336
- try {
337
- // 业务逻辑
338
- } finally {
339
- fairLock.unlock();
340
- }
341
- }
342
-
343
- /**
344
- * 读写锁 - 读多写少场景
345
- */
346
- public void readWriteLock(String bizKey) {
347
- RReadWriteLock rwLock = redissonClient.getReadWriteLock("avatar:rwlock:" + bizKey);
348
-
349
- // 读锁(共享)
350
- rwLock.readLock().lock();
351
- try {
352
- // 读操作
353
- } finally {
354
- rwLock.readLock().unlock();
355
- }
356
-
357
- // 写锁(独占)
358
- rwLock.writeLock().lock();
359
- try {
360
- // 写操作
361
- } finally {
362
- rwLock.writeLock().unlock();
363
- }
364
- }
365
- }
366
- ```
367
-
368
- ## Spring Cache 集成
369
-
370
- ### 启用缓存
371
-
372
- ```java
373
- package com.example;
374
-
375
- import org.springframework.boot.SpringApplication;
376
- import org.springframework.boot.autoconfigure.SpringBootApplication;
377
- import org.springframework.cache.annotation.EnableCaching;
378
-
379
- @EnableCaching
380
- @SpringBootApplication
381
- public class Application {
382
- public static void main(String[] args) {
383
- SpringApplication.run(Application.class, args);
384
- }
385
- }
386
- ```
387
-
388
- ### 使用缓存注解
389
-
390
- ```java
391
- package com.example.service;
392
-
393
- import com.example.entity.User;
394
- import lombok.RequiredArgsConstructor;
395
- import org.springframework.cache.annotation.CacheEvict;
396
- import org.springframework.cache.annotation.CachePut;
397
- import org.springframework.cache.annotation.Cacheable;
398
- import org.springframework.stereotype.Service;
399
-
400
- @Service
401
- @RequiredArgsConstructor
402
- public class UserService {
403
-
404
- private final UserMapper userMapper;
405
-
406
- /**
407
- * 查询时缓存结果
408
- * 缓存 Key: user::123
409
- */
410
- @Cacheable(cacheNames = "user", key = "#id", unless = "#result == null")
411
- public User getById(Long id) {
412
- return userMapper.selectById(id);
413
- }
414
-
415
- /**
416
- * 更新时同步更新缓存
417
- */
418
- @CachePut(cacheNames = "user", key = "#user.id")
419
- public User update(User user) {
420
- userMapper.updateById(user);
421
- return user;
422
- }
423
-
424
- /**
425
- * 删除时清除缓存
426
- */
427
- @CacheEvict(cacheNames = "user", key = "#id")
428
- public void deleteById(Long id) {
429
- userMapper.deleteById(id);
430
- }
431
-
432
- /**
433
- * 清除某个缓存空间的所有数据
434
- */
435
- @CacheEvict(cacheNames = "user", allEntries = true)
436
- public void clearUserCache() {
437
- // 清空 user 缓存空间
438
- }
439
- }
440
- ```
441
-
442
- ### 配置 Redis 缓存管理器
443
-
444
- ```yaml
445
- spring:
446
- cache:
447
- type: redis
448
- redis:
449
- time-to-live: 1800000 # 默认 TTL: 30 分钟(毫秒)
450
- key-prefix: "avatar:" # Key 前缀
451
- use-key-prefix: true
452
- cache-null-values: false # 不缓存 null 值
453
- ```
454
-
455
- ## Key 命名规范
456
-
457
- **必须遵循统一的 Key 命名规范:**
458
-
459
- ```
460
- {appName}:{module}:{bizKey}
461
- ```
462
-
463
- 示例:
464
-
465
- | 场景 | Key 格式 | 示例 |
466
- |------|---------|------|
467
- | 用户缓存 | `avatar:user:{userId}` | `avatar:user:123` |
468
- | 用户 Session | `avatar:session:{sessionId}` | `avatar:session:abc-def-123` |
469
- | 分布式锁 | `avatar:lock:{bizKey}` | `avatar:lock:order-create-456` |
470
- | 接口限流 | `avatar:ratelimit:{api}:{clientIp}` | `avatar:ratelimit:/api/sms:10.0.0.1` |
471
- | 排行榜 | `avatar:rank:{type}` | `avatar:rank:daily-score` |
472
-
473
- **规范要求:**
474
-
475
- 1. **必须使用冒号分隔**,不要使用下划线或点号
476
- 2. **必须包含应用名前缀**,避免多应用共用 Redis 时 Key 冲突
477
- 3. **必须设置 TTL**,禁止使用永不过期的 Key(防止内存泄漏)
478
- 4. **Key 长度控制**,建议不超过 128 字符
479
-
480
- ## 序列化方式选择
481
-
482
- | 序列化方式 | 适用场景 | 优点 | 缺点 |
483
- |-----------|---------|------|------|
484
- | StringRedisSerializer | 简单字符串 | 可读性好 | 只能存字符串 |
485
- | Jackson2JsonRedisSerializer | 对象缓存(推荐) | 可读性好、跨语言 | 需要类型信息 |
486
- | GenericJackson2JsonRedisSerializer | 通用对象 | 自动携带类型信息 | JSON 体积较大 |
487
- | JdkSerializationRedisSerializer | 默认(不推荐) | 无需配置 | 不可读、跨语言困难 |
488
-
489
- **推荐方案:**
490
- - Key 序列化:`StringRedisSerializer`
491
- - Value 序列化:`Jackson2JsonRedisSerializer`
492
- - Hash Key 序列化:`StringRedisSerializer`
493
- - Hash Value 序列化:`Jackson2JsonRedisSerializer`
494
-
495
- ## 最佳实践
496
-
497
- ### 1. 缓存设计
498
-
499
- - **必须设置 TTL**:所有 Key 必须设置过期时间,禁止永久 Key
500
- - **缓存穿透防护**:对不存在的数据缓存空值(短 TTL),或使用布隆过滤器
501
- - **缓存击穿防护**:热点 Key 使用分布式锁重建缓存
502
- - **缓存雪崩防护**:TTL 加随机偏移量,避免大批 Key 同时过期
503
-
504
- ### 2. 分布式锁
505
-
506
- - **必须设置超时时间**:防止死锁,推荐 `tryLock(waitTime, leaseTime, unit)`
507
- - **使用 try-finally**:确保锁一定会被释放
508
- - **检查锁持有者**:释放前检查 `lock.isHeldByCurrentThread()`
509
- - **合理设置 leaseTime**:业务执行时间 + 安全余量
510
-
511
- ### 3. 连接池
512
-
513
- - **合理配置连接数**:根据并发量设置 `max-active`,建议 CPU 核数 * 2
514
- - **设置最小空闲**:`min-idle` 设为 2-4,避免冷启动延迟
515
- - **连接超时**:`max-wait` 建议 3-5 秒,不宜过长
516
-
517
- ### 4. 数据一致性
518
-
519
- - **延迟双删策略**:先删缓存 -> 更新数据库 -> 延迟再删缓存
520
- - **最终一致性**:通过消息队列异步更新缓存
521
- - **读写锁**:对一致性要求高的场景使用 Redisson 读写锁
522
-
523
- ## 常见问题
524
-
525
- ### 1. Connection refused(连接被拒绝)
526
-
527
- **原因**:Redis 服务未启动或配置错误
528
-
529
- **解决**:
530
- - 检查 Redis 服务是否启动:`redis-cli ping`
531
- - 检查 `spring.data.redis.host` 和 `port` 配置是否正确
532
- - 检查防火墙是否允许访问 Redis 端口
533
- - 检查 Redis `bind` 配置和 `protected-mode`
534
-
535
- ### 2. Timeout(连接超时)
536
-
537
- **原因**:连接池耗尽或网络延迟
538
-
539
- **解决**:
540
- - 增大连接池 `max-active` 配置
541
- - 检查是否存在慢查询命令(如 KEYS *),使用 `redis-cli slowlog get` 查看
542
- - 检查 Redis 内存使用情况:`redis-cli info memory`
543
- - 调整 `timeout` 和 `max-wait` 配置
544
-
545
- ### 3. 序列化异常(SerializationException)
546
-
547
- **原因**:序列化/反序列化不匹配
548
-
549
- **解决**:
550
- - 确保 RedisTemplate 的序列化器配置一致
551
- - 使用 Jackson2JsonRedisSerializer 时确保对象有默认构造函数
552
- - 检查类路径变更导致的反序列化失败
553
- - 清理旧序列化格式的缓存数据
24
+ ---
554
25
 
555
- ### 4. 分布式锁未释放
26
+ ## 行为准则
556
27
 
557
- **原因**:业务异常导致 unlock 未执行
28
+ 1. **回答要具体**:引用具体的 Client 类名、方法名
29
+ 2. **主动提醒**:
30
+ - 需要 `@EnableRedis` 注解才能启用模块
31
+ - 分布式锁使用完毕必须释放,建议 try-finally 或回调方式
32
+ - Key 命名规范:`业务:类型:ID`
33
+ 3. **使用中文回答**
558
34
 
559
- **解决**:
560
- - 使用 try-finally 确保锁释放
561
- - 设置合理的 leaseTime 作为兜底
562
- - 检查是否在异步线程中释放锁(锁绑定线程)
563
- - 使用 Redisson 看门狗机制自动续期
35
+ ---
564
36
 
565
- ### 5. 缓存与数据库不一致
37
+ ## 文档读取路由
566
38
 
567
- **原因**:并发更新导致缓存脏数据
39
+ > 所有路径相对于 skill 目录 `docs/skills/avatar-boot-starter-redis-skill/`
568
40
 
569
- **解决**:
570
- - 采用 Cache-Aside 模式:先更新数据库,再删除缓存
571
- - 使用延迟双删策略保证最终一致性
572
- - 设置合理的 TTL,允许短时间不一致
573
- - 高一致性场景使用分布式锁
41
+ | 用户需求 | 需读取的文件 |
42
+ |:--|:--|
43
+ | 快速接入 / 配置说明 | `references/快速接入与配置.md` |
44
+ | 数据结构操作 / 缓存操作 | `references/数据操作.md` |
45
+ | 分布式锁 / 限流 / 布隆过滤器 | `references/高级功能.md` |
574
46
 
575
- ## 依赖版本
47
+ ---
576
48
 
577
- - Redisson: 3.40.2
578
- - Spring Data Redis: 由 Spring Boot 3.5.3 BOM 管理
579
- - Lettuce: 由 Spring Boot 3.5.3 BOM 管理
580
- - Java: 21
49
+ ## 通用参考信息
581
50
 
582
- ## 参考文档
51
+ ### 核心 Client 速查
583
52
 
584
- - [Spring Data Redis 官方文档](https://docs.spring.io/spring-data/redis/reference/)
585
- - [Redisson 官方文档](https://github.com/redisson/redisson/wiki)
586
- - [Spring Cache 抽象](https://docs.spring.io/spring-framework/reference/integration/cache.html)
53
+ | Client | 用途 |
54
+ |:--|:--|
55
+ | `RedisStringClient` | String 操作(set/get/increment/multiSet) |
56
+ | `RedisHashClient` | Hash 操作(put/get/getAll/increment) |
57
+ | `RedisSetClient` | Set 操作(add/members/isMember/remove) |
58
+ | `RedisZSetClient` | ZSet 操作(add/reverseRange/score/incrementScore) |
59
+ | `RedisCacheClient` | 缓存操作(set/get/delete/deletePattern) |
60
+ | `RedissonLockClient` | 分布式锁(lock/tryLock/unlock) |
61
+ | `RedisRateLimiterClient` | 限流(tryAcquire/slidingWindowLimit) |
62
+ | `RedisBloomFilterClient` | 布隆过滤器(init/add/contains) |
@@ -0,0 +1,78 @@
1
+ # Redis 快速接入与配置
2
+
3
+ ## 1. 添加依赖
4
+
5
+ ```xml
6
+ <dependency>
7
+ <groupId>com.iflytek.avatar.boot</groupId>
8
+ <artifactId>avatar-boot-starter-redis</artifactId>
9
+ </dependency>
10
+ ```
11
+
12
+ ## 2. 启用 Redis 模块
13
+
14
+ ```java
15
+ @SpringBootApplication
16
+ @EnableRedis
17
+ public class Application {
18
+ public static void main(String[] args) {
19
+ SpringApplication.run(Application.class, args);
20
+ }
21
+ }
22
+ ```
23
+
24
+ ## 3. 配置连接
25
+
26
+ ```yaml
27
+ spring:
28
+ data:
29
+ redis:
30
+ host: 127.0.0.1
31
+ port: 6379
32
+ password: ${REDIS_PASSWORD}
33
+ database: 0
34
+ timeout: 3000ms
35
+ lettuce:
36
+ pool:
37
+ max-active: 8
38
+ max-idle: 8
39
+ min-idle: 0
40
+ max-wait: -1ms
41
+
42
+ # Redisson 配置(分布式锁/限流/布隆过滤器需要)
43
+ redisson:
44
+ single-server-config:
45
+ address: redis://127.0.0.1:6379
46
+ password: ${REDIS_PASSWORD}
47
+ database: 0
48
+ connection-pool-size: 64
49
+ connection-minimum-idle-size: 32
50
+ timeout: 3000
51
+ connect-timeout: 10000
52
+ ```
53
+
54
+ ## 配置说明
55
+
56
+ ### Spring Data Redis
57
+
58
+ | 配置项 | 说明 | 默认值 |
59
+ |:--|:--|:--|
60
+ | `spring.data.redis.host` | Redis 主机 | `localhost` |
61
+ | `spring.data.redis.port` | Redis 端口 | `6379` |
62
+ | `spring.data.redis.database` | 数据库索引 | `0` |
63
+ | `spring.data.redis.timeout` | 命令超时时间 | `3000ms` |
64
+ | `lettuce.pool.max-active` | 最大连接数 | `8` |
65
+
66
+ ### Redisson
67
+
68
+ | 配置项 | 说明 | 默认值 |
69
+ |:--|:--|:--|
70
+ | `redisson.single-server-config.address` | Redis 地址 | `redis://localhost:6379` |
71
+ | `redisson.single-server-config.connection-pool-size` | 连接池大小 | `64` |
72
+ | `redisson.single-server-config.timeout` | 命令超时(ms) | `3000` |
73
+
74
+ ## 注意事项
75
+
76
+ - 需要 `@EnableRedis` 注解才能启用模块
77
+ - 分布式锁、限流、布隆过滤器需要同时配置 `redisson.*`
78
+ - RedisTemplate 默认使用 JSON 序列化,确保对象可序列化