本文介绍在 Spring Boot 中使用 Redis 的依赖安装、基础配置、通用工具类编写与常见使用方法,包含字符串、对象、哈希、集合、分布式锁与限流等场景。示例偏向 Lombok 与 Spring Boot 3/Spring Data Redis(Lettuce)。

依赖安装

<!-- Maven -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>
// Gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

基础配置

# application.yml
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: ${REDIS_PASSWORD:}
    database: 0
    timeout: 2000
    lettuce:
      pool:
        max-active: 16
        max-idle: 8
        min-idle: 2
// RedisConfig.java
package com.example.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@RequiredArgsConstructor
public class RedisConfig {

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        StringRedisSerializer keySerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(customMapper());
        template.setKeySerializer(keySerializer);
        template.setHashKeySerializer(keySerializer);
        template.setValueSerializer(valueSerializer);
        template.setHashValueSerializer(valueSerializer);
        template.afterPropertiesSet();
        return template;
    }

    private ObjectMapper customMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        return mapper;
    }
}

通用工具类编写

// RedisUtils.java
package com.example.redis;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@RequiredArgsConstructor
public class RedisUtils {
    private final StringRedisTemplate stringRedis;
    private final RedisTemplate<String, Object> redis;

    // 字符串操作
    public void set(String key, String value, long ttlSeconds) {
        if (ttlSeconds > 0) {
            stringRedis.opsForValue().set(key, value, Duration.ofSeconds(ttlSeconds));
        } else {
            stringRedis.opsForValue().set(key, value);
        }
    }

    public String get(String key) { return stringRedis.opsForValue().get(key); }
    public Boolean setIfAbsent(String key, String value, long ttlMillis) {
        return stringRedis.opsForValue().setIfAbsent(key, value, Duration.ofMillis(ttlMillis));
    }
    public Long incr(String key, long delta) { return stringRedis.opsForValue().increment(key, delta); }
    public Boolean expire(String key, long ttlSeconds) { return stringRedis.expire(key, ttlSeconds, TimeUnit.SECONDS); }
    public Boolean del(String key) { return stringRedis.delete(key); }

    // 对象操作(JSON 序列化)
    public void setObj(String key, Object value, long ttlSeconds) {
        if (ttlSeconds > 0) redis.opsForValue().set(key, value, ttlSeconds, TimeUnit.SECONDS);
        else redis.opsForValue().set(key, value);
    }
    public Object getObj(String key) { return redis.opsForValue().get(key); }

    // Hash
    public void hset(String key, String field, Object value) { redis.opsForHash().put(key, field, value); }
    public Object hget(String key, String field) { return redis.opsForHash().get(key, field); }
    public void hmset(String key, Map<String, Object> map) { redis.opsForHash().putAll(key, map); }

    // Set
    public Long sadd(String key, String... members) { return stringRedis.opsForSet().add(key, members); }
    public Long srem(String key, String... members) { return stringRedis.opsForSet().remove(key, (Object[]) members); }
    public Boolean sismember(String key, String member) { return stringRedis.opsForSet().isMember(key, member); }

    // 简易分布式锁(基于 setIfAbsent + 过期 + Lua 释放)
    public Boolean tryLock(String key, String token, long ttlMillis) {
        return stringRedis.opsForValue().setIfAbsent(key, token, Duration.ofMillis(ttlMillis));
    }
    public boolean releaseLock(String key, String token) {
        String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long res = stringRedis.execute(new DefaultRedisScript<>(lua, Long.class), Collections.singletonList(key), token);
        return res != null && res > 0;
    }
}

使用方法

缓存读写(Cache Aside)

// UserService.java
package com.example.user;

import com.example.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class UserService {
    private final RedisUtils redis;
    private final UserRepository repo;

    public User getById(Long id) {
        String key = "user:" + id;
        Object cached = redis.getObj(key);
        if (cached instanceof User u) { return u; }
        User u = repo.findById(id).orElse(null);
        if (u != null) { redis.setObj(key, u, 900); }
        return u;
    }

    public void update(User u) {
        repo.save(u);
        redis.del("user:" + u.getId());
    }
}

限流(每分钟 N 次)

// RateLimiter.java
package com.example.limiter;

import com.example.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class RateLimiter {
    private final RedisUtils redis;

    public boolean allow(String key, int limit) {
        String k = "rate:" + key + ":" + (System.currentTimeMillis() / 60000);
        Long count = redis.incr(k, 1);
        if (count != null && count == 1) { redis.expire(k, 60); }
        return count != null && count <= limit;
    }
}

分布式锁

// LockExampleService.java
package com.example.lock;

import com.example.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class LockExampleService {
    private final RedisUtils redis;

    public void criticalSection(String key) {
        String token = UUID.randomUUID().toString();
        if (Boolean.TRUE.equals(redis.tryLock("lock:" + key, token, 5000))) {
            try {
                // 关键业务逻辑
            } finally {
                redis.releaseLock("lock:" + key, token);
            }
        }
    }
}

工程化建议

  • 统一 Key 规范:<业务>:<资源>:<标识>,避免冲突与大 Key。
  • 所有缓存必须设置 TTL;更新时先写库再删缓存,防止脏读。
  • 对对象使用 JSON 序列化并保持稳定的字段结构;避免存放敏感信息。
  • 监控与告警:命中率、慢查询、连接池、内存使用与淘汰策略。
  • 生产环境优先使用 Sentinel 或 Cluster,并设置超时与重试策略。
  • 如需更强的锁语义,考虑使用 Redisson;或在 Lua 中加入续租与重入逻辑。

常见问题

  • 序列化不一致导致读取报错:统一 RedisTemplate 的序列化器配置。
  • 连接耗尽:合理设置连接池与超时时间,避免阻塞操作。
  • 热点 Key:利用本地缓存、分片 Key、随机过期时间减少雪崩与击穿。
  • 大量批量写:考虑使用 Pipeline 或批处理,减少 RTT。

总结

  • 通过规范化的依赖与配置、统一的 RedisTemplate 序列化策略、通用工具类与清晰的使用模式(缓存、限流、锁),可在 Spring Boot 项目中稳定地发挥 Redis 的高性能与可扩展能力。