SpringBoot + Redis 配置详解

SpringBoot + Redis 配置详解

本文将详细介绍SpringBoot与Redis的整合配置,包括依赖引入、连接配置、序列化设置、缓存注解使用等内容,帮助开发者快速实现Redis缓存功能。

一、依赖配置

首先在pom.xml中添加必要的依赖:

xml 复制代码
<!-- Redis 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池依赖(Spring Boot 2.x 默认使用 Lettuce 客户端) -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!-- 可选:如果使用 Jedis 客户端替代 Lettuce -->
<!-- <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency> -->

二、基本连接配置 (application.yml)

application.yml中配置Redis连接信息:

yaml 复制代码
spring:
  redis:
    # Redis 服务器地址
    host: localhost
    # Redis 端口
    port: 6379
    # Redis 密码(若未设置密码,可省略此配置)
    password: 123456
    # 数据库索引(Redis支持0-15共16个数据库)
    database: 0
    # 连接超时时间(毫秒)
    timeout: 3000ms
    
    # Lettuce连接池配置(Spring Boot 2.x 默认)
    lettuce:
      pool:
        # 最大活跃连接数
        max-active: 8
        # 最大空闲连接数
        max-idle: 8
        # 最小空闲连接数
        min-idle: 2
        # 连接池最大阻塞等待时间
        max-wait: 1000ms
    
    # 或使用Jedis连接池配置(需要引入Jedis依赖)
    # jedis:
    #   pool:
    #     max-active: 15
    #     max-idle: 10
    #     min-idle: 5
    #     max-wait: 5000ms
  
  # 缓存配置
  cache:
    # 缓存类型:指定为Redis
    type: redis
    # Redis缓存配置
    redis:
      # 缓存过期时间
      time-to-live: 3600000ms
      # 是否允许缓存空值(防止缓存穿透)
      cache-null-values: true
      # 缓存键前缀
      key-prefix: "spring-boot-redis:"
      # 是否使用键前缀
      use-key-prefix: true

三、RedisTemplate 配置类

创建自定义配置类,配置RedisTemplate序列化方式和各种Operations:

java 复制代码
@Configuration
@EnableCaching
public class RedisConfig {
    
    /**
     * 配置自定义的RedisTemplate
     * 设置Key和Value的序列化方式
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        
        // 设置连接工厂
        redisTemplate.setConnectionFactory(factory);
        
        // 设置Key序列化器
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        
        // 设置Value序列化器(可选择不同的序列化方式)
        // 1. JDK序列化(默认,但可读性差)
        redisTemplate.setValueSerializer(RedisSerializer.java());
        redisTemplate.setHashValueSerializer(RedisSerializer.java());
        
        // 2. JSON序列化(推荐,可读性好)
        /*
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        */
        
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    
    /**
     * 配置StringRedisTemplate(专用字符串操作)
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }
    
    /**
     * 配置HashOperations
     */
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }
    
    /**
     * 配置ValueOperations
     */
    @Bean
    public ValueOperations<String, String> valueOperations(StringRedisTemplate stringRedisTemplate) {
        return stringRedisTemplate.opsForValue();
    }
    
    /**
     * 配置ListOperations
     */
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }
    
    /**
     * 配置SetOperations
     */
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }
    
    /**
     * 配置ZSetOperations
     */
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }
    
    /**
     * 配置缓存管理器
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1))  // 设置缓存有效期
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.java()))
                .disableCachingNullValues();  // 不缓存空值
        
        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
    }
}

四、使用RedisTemplate操作Redis

1. 注入RedisTemplate

java 复制代码
@Service
public class RedisService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // 或使用StringRedisTemplate(更适合纯字符串操作)
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
}

2. 基本操作示例

java 复制代码
@Service
public class RedisService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    // String操作
    public void setString(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }
    
    public String getString(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
    
    // 对象操作
    public void setObject(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }
    
    public Object getObject(String key) {
        return redisTemplate.opsForValue().get(key);
    }
    
    // 带过期时间的设置
    public void setStringWithExpire(String key, String value, long timeout, TimeUnit unit) {
        stringRedisTemplate.opsForValue().set(key, value, timeout, unit);
    }
    
    // 删除操作
    public void delete(String key) {
        redisTemplate.delete(key);
    }
    
    // 判断key是否存在
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }
    
    // Hash操作
    public void putHash(String key, String hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }
    
    public Object getHash(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }
    
    // List操作
    public void leftPush(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }
    
    public Object leftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }
}

五、使用缓存注解

1. 启用缓存

在主应用类或配置类上添加@EnableCaching注解:

java 复制代码
@SpringBootApplication
@EnableCaching
public class SpringBootRedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootRedisApplication.class, args);
    }
}

2. 常用缓存注解使用

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    /**
     * 将查询结果缓存
     */
    @Cacheable(value = "user", key = "#id")
    public User getUserById(Long id) {
        System.out.println("从数据库查询用户信息,id: " + id);
        return userRepository.findById(id).orElse(null);
    }
    
    /**
     * 更新缓存
     */
    @CachePut(value = "user", key = "#user.id")
    public User updateUser(User user) {
        System.out.println("更新用户信息,id: " + user.getId());
        return userRepository.save(user);
    }
    
    /**
     * 删除缓存
     */
    @CacheEvict(value = "user", key = "#id")
    public void deleteUser(Long id) {
        System.out.println("删除用户信息,id: " + id);
        userRepository.deleteById(id);
    }
    
    /**
     * 清除所有缓存
     */
    @CacheEvict(value = "user", allEntries = true)
    public void clearCache() {
        System.out.println("清除所有用户缓存");
    }
}

六、序列化方式选择

Spring Data Redis提供多种序列化方式:

  1. JdkSerializationRedisSerializer

    • 默认序列化方式
    • 优点:支持任何可序列化对象
    • 缺点:序列化后数据体积大,可读性差
  2. Jackson2JsonRedisSerializer

    • JSON序列化,可读性好
    • 优点:序列化后数据体积小,可读性高
    • 缺点:需要配置类型信息以支持反序列化到具体类型
  3. StringRedisSerializer

    • 字符串序列化,主要用于键
    • 优点:高效,可读性好
    • 缺点:只能序列化字符串
  4. GenericJackson2JsonRedisSerializer

    • 通用JSON序列化
    • 优点:自动包含类型信息,使用方便
    • 缺点:序列化结果会包含类型信息,数据量稍大

七、Redis连接池配置说明

Lettuce vs Jedis

Spring Boot 2.x默认使用Lettuce作为Redis客户端,相比Jedis:

  • Lettuce

    • 基于Netty的异步客户端
    • 线程安全
    • 支持异步操作
    • 默认选择
  • Jedis

    • 同步阻塞客户端
    • 非线程安全,需要使用连接池
    • 操作简单直观

连接池参数调优建议

  • max-active:根据并发量设置,推荐为CPU核心数的10倍左右
  • max-idle:保持的最大空闲连接数,建议与max-active一致
  • min-idle:保持的最小空闲连接数,建议设置为5-10
  • max-wait:获取连接的最大等待时间,建议设置为1000-5000ms
  • timeout:连接超时时间,建议设置为3000-5000ms

八、常见问题与解决方案

  1. 缓存穿透问题

    • 解决方案:缓存空值(cache-null-values: true)或使用布隆过滤器
  2. 缓存击穿问题

    • 解决方案:热点数据设置永不过期或使用互斥锁
  3. 缓存雪崩问题

    • 解决方案:设置随机过期时间或使用多级缓存
  4. 序列化问题

    • 解决方案:确保对象实现Serializable接口,或使用JSON序列化
  5. 连接池耗尽

    • 解决方案:增加连接池大小,检查是否有连接未正确释放

通过以上配置和最佳实践,可以有效实现SpringBoot与Redis的整合,充分利用Redis的高性能缓存能力,提升应用性能。

相关推荐
oak隔壁找我3 小时前
SpringBoot + MyBatis 配置详解
java·数据库·后端
爱分享的鱼鱼3 小时前
技术方案文档案例——电商直播平台
后端
学习OK呀3 小时前
java 有了Spring AI的扶持下
后端
躺平的赶海人3 小时前
C# Dictionary 线程安全指南:多线程下操作 Dictionary<string, DateTime> 的加锁策略
java·安全·c#
帧栈3 小时前
开发避坑指南(64):修复IllegalArgumentException:参数值类型与期望类型不匹配
java·数据库
canonical_entropy3 小时前
最小变更成本 vs 最小信息表达:第一性原理的比较
后端
渣哥3 小时前
代理选错,性能和功能全翻车!Spring AOP 的默认技术别再搞混
javascript·后端·面试
坐不住的爱码3 小时前
ArrayList和LinkedList的区别
java
java1234_小锋3 小时前
什么是Java三高架构?
java·开发语言·架构