Redis 与 Java 整合:缓存穿透、击穿、雪崩解决方案
·
Redis 与 Java 整合方案
以下代码示例基于 Spring Boot 和 Redis 实现缓存穿透、击穿、雪崩的解决方案,使用 Lettuce 作为 Redis 客户端。
依赖配置
确保 pom.xml 包含以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
缓存穿透解决方案
通过布隆过滤器或空值缓存避免恶意查询不存在的 key。
@Service
public class CacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public Object getDataWithPenetrationProtection(String key) {
// 1. 先查缓存
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return "NULL".equals(value) ? null : value; // 空值标识处理
}
// 2. 模拟数据库查询
Object dbValue = getFromDatabase(key);
if (dbValue == null) {
// 空结果也缓存,设置较短过期时间
redisTemplate.opsForValue().set(key, "NULL", 5, TimeUnit.MINUTES);
return null;
}
// 3. 正常缓存数据
redisTemplate.opsForValue().set(key, dbValue, 30, TimeUnit.MINUTES);
return dbValue;
}
}
缓存击穿解决方案
使用互斥锁防止热点 key 失效时大量请求直达数据库。
public Object getDataWithBreakdownProtection(String key) {
// 1. 尝试获取缓存
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
// 2. 获取分布式锁
String lockKey = key + "_lock";
boolean locked = false;
try {
locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (locked) {
// 3. 再次检查缓存(双重检查锁)
value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
// 4. 查询数据库并重建缓存
value = getFromDatabase(key);
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
return value;
} else {
// 等待重试
Thread.sleep(50);
return getDataWithBreakdownProtection(key);
}
} finally {
if (locked) {
redisTemplate.delete(lockKey);
}
}
}
缓存雪崩解决方案
通过随机过期时间避免大量 key 同时失效。
public Object getDataWithAvalancheProtection(String key) {
// 1. 尝试获取缓存
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
// 2. 查询数据库
value = getFromDatabase(key);
// 3. 设置缓存时添加随机过期时间(基础30分钟 + 随机10分钟)
Random random = new Random();
int expireTime = 30 + random.nextInt(10);
redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.MINUTES);
return value;
}
辅助方法
private Object getFromDatabase(String key) {
// 模拟数据库查询
return "data_from_db_" + key;
}
配置建议
在 application.yml 中配置 Redis 连接池:
spring:
redis:
host: localhost
port: 6379
lettuce:
pool:
max-active: 16
max-wait: -1ms
max-idle: 8
min-idle: 4
注意事项
- 分布式锁实现需考虑更严谨的超时和原子性问题
- 生产环境建议使用 Redisson 等专业库实现分布式锁
- 布隆过滤器需额外引入 Guava 或 Redis 模块支持
更多推荐




所有评论(0)