SpringBoot集成Redis操作缓存

wen java案例 1

本文目录导读:

SpringBoot集成Redis操作缓存

  1. 添加依赖
  2. 配置文件
  3. Redis配置类
  4. 缓存注解使用
  5. 手动操作Redis
  6. Controller示例
  7. 高级配置
  8. 缓存策略建议

我将详细介绍SpringBoot集成Redis实现缓存的完整方案。

添加依赖

Maven依赖

<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>
<!-- JSON序列化支持 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

配置文件

application.yml

spring:
  redis:
    host: localhost
    port: 6379
    password: 
    database: 0
    timeout: 10000ms
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: -1ms
  cache:
    type: redis
    redis:
      time-to-live: 3600000ms  # 默认缓存过期时间1小时
      cache-null-values: false  # 是否缓存空值

Redis配置类

@Configuration
@EnableCaching
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        // JSON序列化配置
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);
        // String序列化配置
        StringRedisSerializer stringSerializer = new StringRedisSerializer();
        // key使用String序列化
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        // value使用JSON序列化
        template.setValueSerializer(jacksonSerializer);
        template.setHashValueSerializer(jacksonSerializer);
        template.afterPropertiesSet();
        return template;
    }
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                    .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                    .fromSerializer(new Jackson2JsonRedisSerializer<>(Object.class)))
                .disableCachingNullValues();
        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }
}

缓存注解使用

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private String username;
    private String email;
    private Integer age;
}

Service层实现缓存

@Service
@Slf4j
public class UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 使用@Cacheable注解实现缓存
     */
    @Cacheable(value = "users", key = "#id", unless = "#result == null")
    public User getUserById(Long id) {
        log.info("查询数据库获取用户: {}", id);
        return userMapper.findById(id);
    }
    /**
     * 根据条件缓存
     */
    @Cacheable(value = "users", key = "#username", 
               condition = "#username.length() > 3")
    public User getUserByUsername(String username) {
        log.info("查询数据库获取用户: {}", username);
        return userMapper.findByUsername(username);
    }
    /**
     * 使用@CachePut更新缓存
     */
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        log.info("更新用户信息: {}", user);
        userMapper.update(user);
        return user;
    }
    /**
     * 使用@CacheEvict删除缓存
     */
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        log.info("删除用户: {}", id);
        userMapper.deleteById(id);
    }
    /**
     * 清除所有用户缓存
     */
    @CacheEvict(value = "users", allEntries = true)
    public void clearAllUserCache() {
        log.info("清除所有用户缓存");
    }
    /**
     * 组合使用注解
     */
    @Caching(
        cacheable = {
            @Cacheable(value = "users", key = "#username")
        },
        put = {
            @CachePut(value = "users", key = "#result.id", 
                     condition = "#result != null")
        }
    )
    public User findOrCreateUser(String username) {
        User user = userMapper.findByUsername(username);
        if (user == null) {
            user = new User();
            user.setUsername(username);
            userMapper.insert(user);
        }
        return user;
    }
}

手动操作Redis

@Service
@Slf4j
public class RedisService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // 字符串操作
    public void setValue(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }
    public void setValueWithExpire(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }
    public Object getValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }
    // List操作
    public void leftPush(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }
    public Object rightPop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }
    public List<Object> getList(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }
    // Set操作
    public void addToSet(String key, Object... values) {
        redisTemplate.opsForSet().add(key, values);
    }
    public Set<Object> getSetMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }
    // Hash操作
    public void hashPut(String key, String hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }
    public Object hashGet(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }
    public Map<Object, Object> hashGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }
    // 分布式锁
    public boolean tryLock(String key, String value, long expireTime) {
        return Boolean.TRUE.equals(
            stringRedisTemplate.opsForValue()
                .setIfAbsent(key, value, expireTime, TimeUnit.SECONDS)
        );
    }
    public void unlock(String key, String value) {
        String currentValue = stringRedisTemplate.opsForValue().get(key);
        if (currentValue != null && currentValue.equals(value)) {
            stringRedisTemplate.delete(key);
        }
    }
    // 删除操作
    public boolean delete(String key) {
        return Boolean.TRUE.equals(redisTemplate.delete(key));
    }
    public long deletePattern(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys != null && !keys.isEmpty()) {
            return redisTemplate.delete(keys);
        }
        return 0;
    }
    // 过期时间操作
    public boolean expire(String key, long timeout, TimeUnit unit) {
        return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
    }
    public long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }
}

Controller示例

@RestController
@RequestMapping("/api/users")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private RedisService redisService;
    @GetMapping("/{id}")
    public Result<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return Result.success(user);
    }
    @PostMapping
    public Result<User> createUser(@RequestBody User user) {
        // 手动缓存
        redisService.setValueWithExpire(
            "user:" + 1, 
            user, 
            1, 
            TimeUnit.HOURS
        );
        return Result.success(user);
    }
    @PutMapping
    public Result<User> updateUser(@RequestBody User user) {
        return Result.success(userService.updateUser(user));
    }
    @DeleteMapping("/{id}")
    public Result<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return Result.success();
    }
}

高级配置

自定义Key生成器

@Component
public class CustomKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder key = new StringBuilder();
        key.append(target.getClass().getSimpleName()).append(":");
        key.append(method.getName()).append(":");
        for (Object param : params) {
            if (param != null) {
                key.append(param.toString()).append("_");
            }
        }
        return key.toString().replaceAll("_$", "");
    }
}

自定义缓存异常处理

@Component
@Slf4j
public class RedisCacheErrorHandler implements CacheErrorHandler {
    @Override
    public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
        log.error("Redis GET error - cache: {}, key: {}", cache.getName(), key, exception);
    }
    @Override
    public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
        log.error("Redis PUT error - cache: {}, key: {}", cache.getName(), key, exception);
    }
    @Override
    public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
        log.error("Redis EVICT error - cache: {}, key: {}", cache.getName(), key, exception);
    }
    @Override
    public void handleCacheClearError(RuntimeException exception, Cache cache) {
        log.error("Redis CLEAR error - cache: {}", cache.getName(), exception);
    }
}

缓存策略建议

  1. 缓存穿透防护

    • 使用布隆过滤器
    • 缓存空对象(设置较短的过期时间)
  2. 缓存雪崩防护

    • 设置不同的过期时间
    • 使用缓存预热
    • 使用多级缓存
  3. 缓存击穿防护

    • 使用互斥锁
    • 热点数据设置永不过期
  4. 性能优化

    • 合理设置序列化方式
    • 使用连接池
    • 批量操作使用pipeline

这个方案提供了完整的Redis缓存集成方案,包括注解缓存和手动缓存操作,可以根据实际需求选择合适的实现方式。

抱歉,评论功能暂时关闭!