【Spring Boot】集成Redis超详细指南 Redis在Spring Boot中的应用场景

一、Redis简介与Spring Boot集成概述

Redis(Remote Dictionary Server)是一个开源的高性能键值对存储系统,它支持多种数据结构,包括字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。Redis以其出色的性能、丰富的数据结构和原子操作而闻名,常被用作数据库、缓存和消息中间件。

1.1 Redis在Spring Boot中的应用场景

  1. 缓存系统:减轻数据库压力,提高系统响应速度
  2. 会话存储:分布式会话管理
  3. 计数器:如网站访问量统计
  4. 排行榜:利用有序集合实现
  5. 消息队列:使用List或发布/订阅模式
  6. 分布式锁:实现跨JVM的互斥访问

1.2 Spring Data Redis简介

Spring Data Redis是Spring框架提供的用于简化Redis访问的模块,它提供了:

  • 简化的配置和自动装配
  • RedisTemplate和StringRedisTemplate模板类
  • 对Redis各种数据结构的封装
  • 与Spring Cache抽象的无缝集成
  • 异常转换为Spring的DataAccessException体系

二、环境准备与项目创建

2.1 环境要求

  1. 开发环境:
    • JDK 1.8或更高版本
    • Maven 3.2+或Gradle 4.x+
    • IDE(IntelliJ IDEA或Eclipse)
  2. Redis服务器:
    • Redis 3.0或更高版本
    • 可以是本地安装或远程服务器

2.2 Redis服务器安装与配置

Windows安装:
  1. 下载Windows版Redis:https://github.com/microsoftarchive/redis/releases
  2. 解压并运行redis-server.exe
  3. 默认端口6379,无需密码
Linux安装:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install redis-server

# CentOS/RHEL
sudo yum install epel-release
sudo yum install redis

# 启动Redis
sudo systemctl start redis
sudo systemctl enable redis
基本配置(redis.conf):
# 绑定IP(0.0.0.0表示所有接口)
bind 0.0.0.0

# 保护模式
protected-mode yes

# 端口
port 6379

# 超时(秒)
timeout 300

# 数据库数量
databases 16

# 密码认证
requirepass yourpassword

# 日志级别
loglevel notice

# 持久化配置
save 900 1
save 300 10
save 60 10000

2.3 创建Spring Boot项目

使用Spring Initializr(https://start.spring.io/)创建项目:

  1. 选择Maven项目
  2. 选择Spring Boot版本(推荐2.3.x或更高)
  3. 添加依赖:
    • Spring Web
    • Spring Data Redis
    • Lombok(可选)
  4. 生成并下载项目
    或者使用命令行:
curl https://start.spring.io/starter.zip -d dependencies=web,data-redis,lombok -d type=maven-project -d baseDir=springboot-redis-demo -o springboot-redis-demo.zip

三、详细配置与依赖管理

3.1 Maven依赖详解

完整的pom.xml依赖配置:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Data Redis Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- Lettuce连接池依赖 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- JSON处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

3.2 配置文件详解

application.properties完整配置:
Redis基本配置

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

连接超时(毫秒)

spring.redis.timeout=3000

Lettuce连接池配置

spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.shutdown-timeout=100ms

集群配置(可选)

spring.redis.cluster.nodes=host1:port1,host2:port2,host3:port3
spring.redis.cluster.max-redirects=3

哨兵配置(可选)

spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=host1:port1,host2:port2,host3:port3

缓存配置

spring.cache.type=redis
spring.cache.redis.time-to-live=600000
spring.cache.redis.key-prefix=CACHE_
spring.cache.redis.cache-null-values=true

application.yml配置示例:
spring:
  redis:
    host: localhost
    port: 6379
    password: 
    database: 0
    timeout: 3000
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: -1ms
      shutdown-timeout: 100ms
  cache:
    type: redis
    redis:
      time-to-live: 600000
      key-prefix: CACHE_
      cache-null-values: true

3.3 高级配置类

创建自定义Redis配置类,实现更灵活的配置:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    
    /**
     * 自定义Redis序列化方式
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类会抛出异常
        om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);
        
        // 值采用json序列化
        template.setValueSerializer(jacksonSerializer);
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        
        // 设置hash key和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSerializer);
        template.afterPropertiesSet();
        
        return template;
    }
    
    /**
     * 对字符串类型的数据操作模板
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }
    
    /**
     * 自定义缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);
        
        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30))  // 默认过期时间30分钟
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSerializer))
                .disableCachingNullValues(); // 不缓存空值
        
        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }
    
    /**
     * 自定义缓存key生成策略
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(":");
            sb.append(method.getName());
            for (Object obj : params) {
                if (obj != null) {
                    sb.append(":");
                    sb.append(obj.toString());
                }
            }
            return sb.toString();
        };
    }
}

四、Redis操作实战

4.1 RedisTemplate详解

RedisTemplate是Spring Data Redis提供的核心类,它封装了各种Redis操作:

4.1.1 基本操作示例
@Service
@Slf4j
public class RedisOperationService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 字符串操作
     */
    public void stringOperations() {
        // 设置值
        redisTemplate.opsForValue().set("stringKey", "hello redis");
        
        // 获取值
        String value = (String) redisTemplate.opsForValue().get("stringKey");
        log.info("stringKey value: {}", value);
        
        // 设置过期时间
        redisTemplate.expire("stringKey", 60, TimeUnit.SECONDS);
        
        // 原子性递增
        redisTemplate.opsForValue().increment("counter", 1);
        Long counter = Long.valueOf(redisTemplate.opsForValue().get("counter").toString());
        log.info("counter value: {}", counter);
    }
    
    /**
     * 哈希操作
     */
    public void hashOperations() {
        String hashKey = "user:1001";
        
        // 设置哈希字段
        redisTemplate.opsForHash().put(hashKey, "name", "张三");
        redisTemplate.opsForHash().put(hashKey, "age", "28");
        redisTemplate.opsForHash().put(hashKey, "email", "zhangsan@example.com");
        
        // 获取所有字段
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(hashKey);
        log.info("user:1001 entries: {}", entries);
        
        // 获取单个字段
        String name = (String) redisTemplate.opsForHash().get(hashKey, "name");
        log.info("user:1001 name: {}", name);
    }
    
    /**
     * 列表操作
     */
    public void listOperations() {
        String listKey = "messages";
        
        // 从左侧插入
        redisTemplate.opsForList().leftPush(listKey, "message1");
        redisTemplate.opsForList().leftPush(listKey, "message2");
        
        // 从右侧插入
        redisTemplate.opsForList().rightPush(listKey, "message3");
        
        // 获取列表范围
        List<Object> messages = redisTemplate.opsForList().range(listKey, 0, -1);
        log.info("messages: {}", messages);
        
        // 弹出元素
        Object leftMessage = redisTemplate.opsForList().leftPop(listKey);
        log.info("left pop: {}", leftMessage);
    }
    
    /**
     * 集合操作
     */
    public void setOperations() {
        String setKey = "tags";
        
        // 添加元素
        redisTemplate.opsForSet().add(setKey, "java", "spring", "redis", "mysql");
        
        // 获取所有成员
        Set<Object> members = redisTemplate.opsForSet().members(setKey);
        log.info("tags: {}", members);
        
        // 随机获取一个成员
        Object randomMember = redisTemplate.opsForSet().randomMember(setKey);
        log.info("random tag: {}", randomMember);
    }
    
    /**
     * 有序集合操作
     */
    public void zSetOperations() {
        String zsetKey = "leaderboard";
        
        // 添加成员和分数
        redisTemplate.opsForZSet().add(zsetKey, "player1", 100);
        redisTemplate.opsForZSet().add(zsetKey, "player2", 200);
        redisTemplate.opsForZSet().add(zsetKey, "player3", 150);
        
        // 获取排名
        Set<Object> topPlayers = redisTemplate.opsForZSet().range(zsetKey, 0, 1);
        log.info("top 2 players: {}", topPlayers);
        
        // 获取分数
        Double score = redisTemplate.opsForZSet().score(zsetKey, "player2");
        log.info("player2 score: {}", score);
    }
    
    /**
     * 事务操作
     */
    public void transactionOperations() {
        // 开启事务
        redisTemplate.setEnableTransactionSupport(true);
        
        redisTemplate.multi();
        try {
            redisTemplate.opsForValue().set("tx_key1", "value1");
            redisTemplate.opsForValue().set("tx_key2", "value2");
            // 模拟异常
            // int i = 1 / 0;
            redisTemplate.exec();
        } catch (Exception e) {
            redisTemplate.discard();
            log.error("Transaction error", e);
        } finally {
            redisTemplate.setEnableTransactionSupport(false);
        }
    }
    
    /**
     * 管道操作(批量操作)
     */
    public void pipelineOperations() {
        redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                for (int i = 0; i < 1000; i++) {
                    connection.set(("pipeline_key_" + i).getBytes(), ("value_" + i).getBytes());
                }
                return null;
            }
        });
    }
}

4.2 注解缓存实战

Spring Cache抽象提供了几种缓存注解:

4.2.1 缓存注解详解
  1. @Cacheable:在方法执行前检查缓存,如果缓存存在,则直接返回缓存数据
    • value/cacheNames:指定缓存名称
    • key:缓存键的SpEL表达式
    • condition:缓存条件
    • unless:否决缓存的条件
  2. @CachePut:方法执行后将结果存入缓存
    • 参数同@Cacheable
  3. @CacheEvict:清除缓存
    • allEntries:是否清除所有缓存
    • beforeInvocation:是否在方法执行前清除
  4. @Caching:组合多个缓存操作
  5. @CacheConfig:类级别的共享缓存配置
4.2.2 完整示例
@Service
@CacheConfig(cacheNames = "userCache")
@Slf4j
public class UserService {
    
    // 模拟数据库
    private Map<Long, User> userDB = new HashMap<>();
    
    public UserService() {
        // 初始化测试数据
        userDB.put(1L, new User(1L, "张三", 25));
        userDB.put(2L, new User(2L, "李四", 30));
        userDB.put(3L, new User(3L, "王五", 28));
    }
    
    /**
     * 根据ID查询用户
     * 使用缓存,如果缓存存在则直接返回缓存数据
     */
    @Cacheable(key = "#id", unless = "#result == null")
    public User getUserById(Long id) {
        log.info("查询数据库,用户ID: {}", id);
        return userDB.get(id);
    }
    
    /**
     * 更新用户信息
     * 更新缓存
     */
    @CachePut(key = "#user.id")
    public User updateUser(User user) {
        log.info("更新数据库,用户ID: {}", user.getId());
        userDB.put(user.getId(), user);
        return user;
    }
    
    /**
     * 删除用户
     * 清除缓存
     */
    @CacheEvict(key = "#id")
    public void deleteUser(Long id) {
        log.info("删除数据库记录,用户ID: {}", id);
        userDB.remove(id);
    }
    
    /**
     * 条件缓存
     * 只有当用户年龄大于指定值时才缓存
     */
    @Cacheable(key = "#id", condition = "#result != null && #result.age gt #minAge")
    public User getUserIfAgeGreaterThan(Long id, int minAge) {
        log.info("条件缓存查询,用户ID: {}, 最小年龄: {}", id, minAge);
        User user = userDB.get(id);
        if (user != null && user.getAge() > minAge) {
            return user;
        }
        return null;
    }
    
    /**
     * 多条件组合缓存
     */
    @Caching(
        cacheable = {
            @Cacheable(value = "userByName", key = "#name"),
            @Cacheable(value = "userByAge", key = "#age")
        },
        put = {
            @CachePut(value = "user", key = "#result.id", condition = "#result != null")
        }
    )
    public User getUserByNameAndAge(String name, int age) {
        log.info("多条件查询,姓名: {}, 年龄: {}", name, age);
        return userDB.values().stream()
                .filter(u -> u.getName().equals(name) && u.getAge() == age)
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 清空所有用户缓存
     */
    @CacheEvict(value = {"userCache", "userByName", "userByAge"}, allEntries = true)
    public void clearAllUserCache() {
        log.info("清空所有用户缓存");
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class User implements Serializable {
    private Long id;
    private String name;
    private Integer age;
}

4.3 分布式锁实现

Redis常被用来实现分布式锁,以下是基于Redis的分布式锁实现:

@Service
@Slf4j
public class DistributedLockService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String LOCK_PREFIX = "lock:";
    private static final long DEFAULT_EXPIRE_TIME = 30000; // 30秒
    private static final long DEFAULT_WAIT_TIME = 10000; // 10秒
    private static final long DEFAULT_RETRY_INTERVAL = 100; // 100毫秒
    
    /**
     * 获取锁
     */
    public boolean tryLock(String lockKey, String lockValue, long expireTime) {
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(
                LOCK_PREFIX + lockKey, 
                lockValue, 
                expireTime, 
                TimeUnit.MILLISECONDS
        ));
    }
    
    /**
     * 释放锁
     */
    public boolean releaseLock(String lockKey, String lockValue) {
        String key = LOCK_PREFIX + lockKey;
        
        // 使用Lua脚本保证原子性
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                        "else " +
                        "return 0 " +
                        "end";
        
        Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), 
                Collections.singletonList(key), 
                lockValue);
        
        return result != null && result == 1;
    }
    
    /**
     * 带超时的获取锁
     */
    public boolean lockWithTimeout(String lockKey, String lockValue, 
                                  long expireTime, long waitTime) {
        long endTime = System.currentTimeMillis() + waitTime;
        
        while (System.currentTimeMillis() < endTime) {
            if (tryLock(lockKey, lockValue, expireTime)) {
                return true;
            }
            
            try {
                Thread.sleep(DEFAULT_RETRY_INTERVAL);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        
        return false;
    }
    
    /**
     * 使用锁执行任务
     */
    public <T> T executeWithLock(String lockKey, long expireTime, Supplier<T> supplier) {
        String lockValue = UUID.randomUUID().toString();
        
        try {
            if (!lockWithTimeout(lockKey, lockValue, expireTime, DEFAULT_WAIT_TIME)) {
                throw new RuntimeException("获取锁失败");
            }
            
            return supplier.get();
        } finally {
            releaseLock(lockKey, lockValue);
        }
    }
}

五、高级特性与最佳实践

5.1 Redis数据持久化策略

Spring Boot集成Redis时,需要考虑Redis服务器的持久化配置:

  1. RDB(快照):
    • 定期将内存数据写入磁盘
    • 配置示例:
save 900 1      # 900秒内至少有1个key被修改
save 300 10     # 300秒内至少有10个key被修改
save 60 10000   # 60秒内至少有10000个key被修改
  1. AOF(追加日志):
    • 记录所有写操作命令
    • 配置示例:
appendonly yes
appendfsync everysec  # 每秒同步一次

5.2 缓存穿透、雪崩和击穿解决方案

缓存穿透:
  • 问题:查询不存在的数据,绕过缓存直接访问数据库
  • 解决方案:
    • 缓存空对象
    • 布隆过滤器拦截
缓存雪崩:
  • 问题:大量缓存同时失效,导致数据库压力骤增
  • 解决方案:
    • 设置不同的过期时间
    • 缓存永不过期,通过后台更新
    • 多级缓存
缓存击穿:
  • 问题:热点key失效瞬间,大量请求直接访问数据库
  • 解决方案:
    • 永不过期策略
    • 互斥锁重建缓存

5.3 Redis集群与哨兵模式

集群模式配置:
spring.redis.cluster.nodes=192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379
spring.redis.cluster.max-redirects=3
哨兵模式配置:
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.1.1:26379,192.168.1.2:26379,192.168.1.3:26379

5.4 性能优化建议

  1. 连接池优化:
    • 根据系统负载调整连接池大小
    • 监控连接使用情况
  2. 序列化优化:
    • 使用高效的序列化方式(如Kryo、MessagePack)
    • 避免使用Java原生序列化
  3. 批量操作:
    • 使用pipeline减少网络往返
    • 批量获取/设置数据
  4. 键设计:
    • 使用简洁但有意义的键名
    • 避免过长的键名
    • 使用命名空间(如user:1001:profile)

六、测试与监控

6.1 单元测试示例

@SpringBootTest
@Slf4j
class RedisIntegrationTest {
    
    @Autowired
    private RedisOperationService redisOperationService;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private DistributedLockService distributedLockService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @BeforeEach
    void setUp() {
        // 清空测试数据
        redisTemplate.getConnectionFactory().getConnection().flushDb();
    }
    
    @Test
    void testStringOperations() {
        redisOperationService.stringOperations();
        assertNotNull(redisTemplate.opsForValue().get("stringKey"));
    }
    
    @Test
    void testCacheAnnotations() {
        // 第一次查询,应该访问数据库
        User user1 = userService.getUserById(1L);
        assertNotNull(user1);
        
        // 第二次查询,应该从缓存获取
        User user2 = userService.getUserById(1L);
        assertEquals(user1.getName(), user2.getName());
        
        // 更新用户
        user1.setName("UpdatedName");
        User updatedUser = userService.updateUser(user1);
        assertEquals("UpdatedName", updatedUser.getName());
        
        // 再次查询,应该获取更新后的值
        User user3 = userService.getUserById(1L);
        assertEquals("UpdatedName", user3.getName());
    }
    
    @Test
    void testDistributedLock() {
        String lockKey = "testLock";
        String lockValue = UUID.randomUUID().toString();
        
        // 获取锁
        boolean locked = distributedLockService.tryLock(lockKey, lockValue, 30000);
        assertTrue(locked);
        
        // 再次获取同一个锁应该失败
        boolean lockedAgain = distributedLockService.tryLock(lockKey, "anotherValue", 30000);
        assertFalse(lockedAgain);
        
        // 释放锁
        boolean released = distributedLockService.releaseLock(lockKey, lockValue);
        assertTrue(released);
        
        // 锁释放后可以再次获取
        boolean lockedAfterRelease = distributedLockService.tryLock(lockKey, lockValue, 30000);
        assertTrue(lockedAfterRelease);
    }
    
    @Test
    void testPipelinePerformance() {
        long start = System.currentTimeMillis();
        redisOperationService.pipelineOperations();
        long end = System.currentTimeMillis();
        log.info("Pipeline操作耗时: {} ms", end - start);
        
        // 验证数据
        for (int i = 0; i < 1000; i++) {
            assertNotNull(redisTemplate.opsForValue().get("pipeline_key_" + i));
        }
    }
}

6.2 监控与健康检查

Spring Boot Actuator提供了Redis健康检查端点:

  1. 添加依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  1. 配置application.properties:
management.endpoints.web.exposure.include=health,info
management.endpoint.health.show-details=always
  1. 访问/actuator/health可以查看Redis连接状态

6.3 Redis指标监控

Spring Boot Micrometer集成可以监控Redis指标:

  1. 添加依赖:
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
  1. 配置application.properties:
management.endpoints.web.exposure.include=health,info,prometheus
management.metrics.export.prometheus.enabled=true
  1. 访问/actuator/prometheus可以获取Redis相关指标

七、常见问题与解决方案

7.1 连接问题

问题:无法连接到Redis服务器
解决方案:

  1. 检查Redis服务器是否运行
  2. 检查防火墙设置
  3. 检查Spring Boot配置是否正确
  4. 增加连接超时时间:
spring.redis.timeout=5000

7.2 序列化问题

问题:java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload
解决方案:

  1. 确保存储的对象实现了Serializable接口
  2. 或者配置自定义的序列化器(如前面配置类所示)

7.3 性能问题

问题:Redis操作响应慢
解决方案:

  1. 检查网络延迟
  2. 使用连接池并调整大小
  3. 使用pipeline批量操作
  4. 避免大对象存储

7.4 缓存一致性问题

问题:数据库更新后缓存未同步
解决方案:

  1. 使用@CachePut确保更新操作同步缓存
  2. 实现Cache-aside模式
  3. 考虑使用消息队列同步缓存

八、总结

本文详细介绍了Spring Boot集成Redis的完整过程,包括:

  1. 环境准备与项目创建
  2. 详细配置与依赖管理
  3. Redis操作实战(基本操作、注解缓存、分布式锁)
  4. 高级特性与最佳实践
  5. 测试与监控方案
  6. 常见问题解决方案
    通过本文的学习,您应该能够:
  • 熟练地在Spring Boot项目中集成Redis
  • 使用RedisTemplate进行各种数据结构操作
  • 利用Spring Cache抽象实现声明式缓存
  • 实现分布式锁解决并发问题
  • 优化Redis性能并解决常见问题
    Redis作为高性能的内存数据库,在Spring Boot生态中有着广泛的应用场景。合理使用Redis可以显著提升系统性能,但同时也需要注意缓存一致性、雪崩、穿透等问题。希望本文能够帮助您在项目中更好地使用Redis。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜雨hiyeyu.com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值