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

注意事项

  1. 分布式锁实现需考虑更严谨的超时和原子性问题
  2. 生产环境建议使用 Redisson 等专业库实现分布式锁
  3. 布隆过滤器需额外引入 Guava 或 Redis 模块支持
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐