scaffold-redis -- Redis 缓存工具模块
模块概述
scaffold-redis 是基于 Spring Data Redis 封装的缓存工具模块,提供统一的 RedisCache 工具类,覆盖 String、List、Set、Hash、ZSet 五种数据结构的常用操作,内置自动 Key 前缀管理、空值防穿透、分布式锁原语等能力。引入此模块后自动装配,配合 scaffold.redis.* 配置前缀即可使用。
功能列表
- 自动配置
RedisTemplate<String, Object>(Key 用 String 序列化,Value 用 JSON 序列化带类型信息)
- 自动配置
StringRedisTemplate
- 核心工具类
RedisCache:基本操作、List、Set、Hash、ZSet、计数器、分布式锁
- 自动 Key 前缀管理(通过
scaffold.redis.keyPrefix 配置)
- 空值缓存防穿透(可配置开关和过期时间)
- 自定义 Key 生成器
RedisKeyGenerator(用于 @Cacheable 注解)
- 缓存时间单位枚举
CacheTimeUnit(秒/分/时/天/周/月/年)
配置参数
在 application.yml 中以 scaffold.redis 为前缀配置:
scaffold:
redis:
enabled: true # 是否启用模块
cache-enabled: false # 是否启用注解式缓存(@Cacheable 等)
key-generator-enabled: false # 是否启用自定义 Key 生成器
key-prefix: "scaffold" # 缓存 Key 前缀
default-expire-time: 0 # 默认过期时间(秒),0 表示不设置
cache-null-values: true # 是否缓存空值(防穿透)
null-value-expire-time: 60 # 空值缓存过期时间(秒)
print-key-prefix: false # 是否打印 Key 前缀(便于调试)
key-serializer: STRING # Key 序列化策略:STRING / JSON
value-serializer: JSON # Value 序列化策略:STRING / JSON / JDK
| 参数 |
类型 |
默认值 |
说明 |
enabled |
Boolean |
true |
是否启用 Redis 模块 |
cache-enabled |
Boolean |
false |
是否启用 Spring 注解式缓存 |
key-generator-enabled |
Boolean |
false |
是否启用自定义 Key 生成器 |
key-prefix |
String |
"" |
缓存 Key 前缀,设置后所有 Key 自动拼接 前缀:原始Key |
default-expire-time |
Long |
0 |
默认缓存过期时间(秒),0 表示不设置 |
cache-null-values |
Boolean |
true |
是否缓存空值,防止缓存穿透 |
null-value-expire-time |
Long |
60 |
空值缓存过期时间(秒) |
print-key-prefix |
Boolean |
false |
开发环境调试开关,打印生成的 Key |
key-serializer |
Enum |
STRING |
Key 序列化策略 |
value-serializer |
Enum |
JSON |
Value 序列化策略 |
RedisCache 工具类方法说明
RedisCache 是核心工具类,通过构造函数注入即可使用:
@RequiredArgsConstructor
@Service
public class UserService {
private final RedisCache redisCache;
}
基本操作
| 方法签名 |
说明 |
set(String key, Object value) |
设置缓存(使用默认过期时间) |
set(String key, Object value, Long timeout) |
设置缓存(指定过期秒数,null 使用默认) |
<T> T get(String key) |
获取缓存,不存在返回 null |
<T> T get(String key, Supplier<T> supplier) |
获取缓存,不存在时回调获取并写入 |
<T> T get(String key, Supplier<T> supplier, Long timeout) |
同上,可指定过期时间 |
delete(String key) |
删除缓存 |
delete(Collection<String> keys) |
批量删除 |
deleteByPattern(String pattern) |
按模式删除(如 "user:*") |
hasKey(String key) |
判断缓存是否存在 |
expire(String key, long timeout) |
设置过期时间(秒) |
expire(String key, long timeout, TimeUnit unit) |
设置过期时间(指定单位) |
getExpire(String key) |
获取剩余过期时间(秒),-1 永久,-2 不存在 |
分布式锁原语
| 方法签名 |
说明 |
setIfAbsent(String key, Object value, long timeout, TimeUnit unit) |
SETNX 操作,返回 true 表示获取锁成功 |
List 操作
| 方法签名 |
说明 |
leftPush(String key, Object value) |
左侧入队 |
leftPop(String key) |
左侧出队 |
rightPush(String key, Object value) |
右侧入队 |
rightPop(String key) |
右侧出队 |
range(String key, long start, long end) |
获取指定范围元素 |
listSize(String key) |
获取列表长度 |
Set 操作
| 方法签名 |
说明 |
add(String key, Object... values) |
添加元素 |
isMember(String key, Object value) |
判断元素是否存在 |
members(String key) |
获取所有元素 |
setSize(String key) |
获取集合大小 |
remove(String key, Object... values) |
移除元素 |
Hash 操作
| 方法签名 |
说明 |
hSet(String key, String field, Object value) |
设置哈希字段 |
hGet(String key, String field) |
获取哈希字段值 |
hSetAll(String key, Map<String, Object> map) |
批量设置哈希字段 |
hGetAll(String key) |
获取所有哈希字段 |
hDelete(String key, Object... fields) |
删除哈希字段 |
hHasKey(String key, String field) |
判断哈希字段是否存在 |
hSize(String key) |
获取哈希字段数量 |
ZSet 操作
| 方法签名 |
说明 |
zAdd(String key, Object value, double score) |
添加元素(带分数) |
rangeByScore(String key, double min, double max) |
按分数范围获取元素 |
rank(String key, Object value) |
获取元素排名 |
zRemove(String key, Object... values) |
移除元素 |
zSize(String key) |
获取有序集合大小 |
计数器操作
| 方法签名 |
说明 |
increment(String key, long delta) |
自增(整数) |
increment(String key, double delta) |
自增(浮点数) |
decrement(String key, long delta) |
自减 |
其他
| 方法签名 |
说明 |
clear() |
清空当前前缀下的所有缓存 |
Key 命名规范
模块使用 : 作为分隔符,完整的 Redis Key 格式为:
{keyPrefix}:{原始Key}
例如配置 key-prefix: scaffold 时:
scaffold:user:10001
scaffold:order:20260426001
scaffold:lock:seckill:100
建议业务模块按 模块:业务:标识 的结构组织 Key,例如:
user:info:10001 -- 用户信息缓存
order:detail:20260426001 -- 订单详情缓存
lock:seckill:100 -- 秒杀分布式锁
使用示例
基本缓存
@RequiredArgsConstructor
@Service
public class ProductService {
private final RedisCache redisCache;
public ProductVO getProduct(Long productId) {
// 先查缓存,不存在则查库并写入缓存(30分钟)
return redisCache.get("product:info:" + productId, () -> {
Product product = productRepository.getById(productId);
return BeanCopyUtils.copy(product, ProductVO.class);
}, CacheTimeUnit.MINUTES.toSeconds(30));
}
public void updateProduct(ProductUpdateRequest request) {
productRepository.updateById(BeanCopyUtils.copy(request, Product.class));
// 更新后删除缓存
redisCache.delete("product:info:" + request.getId());
}
}
分布式锁
@RequiredArgsConstructor
@Service
public class SeckillService {
private final RedisCache redisCache;
public boolean seckill(Long userId, Long productId) {
String lockKey = "lock:seckill:" + productId;
Boolean locked = redisCache.setIfAbsent(lockKey, userId, 10, TimeUnit.SECONDS);
if (!Boolean.TRUE.equals(locked)) {
throw new BusinessException("操作太频繁,请稍后再试");
}
try {
return doSeckill(userId, productId);
} finally {
redisCache.delete(lockKey);
}
}
}
缓存预热与批量清理
// 批量预热
Map<String, Object> batch = new HashMap<>();
for (Category cat : categories) {
batch.put("category:" + cat.getId(), cat);
}
batch.forEach((key, value) -> redisCache.set(key, value, CacheTimeUnit.HOURS.toSeconds(2)));
// 按模式清理
redisCache.deleteByPattern("product:list:*");
计数器
// 原子扣减秒杀库存
Long remain = redisCache.decrement("seckill:stock:" + productId, 1);
if (remain < 0) {
redisCache.increment("seckill:stock:" + productId, 1); // 回滚
throw new BusinessException("库存不足");
}
CacheTimeUnit 枚举
| 枚举值 |
秒数 |
说明 |
SECONDS |
1 |
秒 |
MINUTES |
60 |
分钟 |
HOURS |
3600 |
小时 |
DAYS |
86400 |
天 |
WEEKS |
604800 |
周 |
MONTH |
2592000 |
月(30天) |
YEAR |
31536000 |
年(365天) |
提供 toSeconds(long amount) 方法用于换算,以及静态方法 forever()(返回 -1)和 notExpire()(返回 0)。
RedisConstant 常量
| 常量 |
值 |
说明 |
KEY_DELIMITER |
":" |
Key 分隔符 |
PREFIX_DELIMITER |
":" |
前缀分隔符 |
EXPIRE_FOREVER |
-1L |
永不过期 |
DO_NOT_EXPIRE |
0L |
不设置过期时间 |
NULL_VALUE |
"@NULL@" |
空值缓存标识 |
LOCK_PREFIX |
"lock:" |
分布式锁前缀 |
LOCK_DEFAULT_EXPIRE |
30L |
锁默认过期时间(秒) |
自动配置说明
本模块通过 RedisAutoConfiguration 注册以下 Bean:
| Bean |
条件 |
说明 |
RedisTemplate<String, Object> |
classpath 有 RedisTemplate |
Key 用 String 序列化,Value 用 JSON(带类型信息) |
StringRedisTemplate |
classpath 有 RedisTemplate |
原生 String 操作 |
RedisCache |
上述 Bean 均存在 |
核心工具类 |
自动配置通过 @ConditionalOnProperty(prefix = "scaffold.redis", name = "enabled", havingValue = "true", matchIfMissing = true) 控制,默认启用。
注意事项
get(key, supplier) 内部使用双重检查锁(synchronized)防止缓存击穿,适用于高并发场景。
- 空值缓存默认启用(
cacheNullValues: true),存储为 @NULL@ 标识,防止恶意请求穿透到数据库。
deleteByPattern 方法底层使用 KEYS 命令,在大数据量场景下可能阻塞 Redis,生产环境慎用。
clear() 方法依赖 keyPrefix 配置,未配置前缀时无法清空(会打印警告日志)。
- 所有操作失败均抛出
RedisException,可在 Service 层捕获或由 GlobalExceptionHandler 兜底处理。