Spring Boot整合Redis

引言

Redis作为高性能的键值存储数据库,在缓存、会话管理、排行榜等场景中被广泛应用。Spring Boot通过Spring Data Redis提供了与Redis的无缝整合能力,使开发者能够快速实现高效的数据缓存与存储。本文将手把手教你如何在Spring Boot项目中整合Redis,并通过实际案例展示其核心用法。


一、为什么选择Redis?

1. Redis的核心优势
  • 高性能:数据存储在内存中,读写速度达10万+/秒。
  • 丰富的数据结构:支持字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(ZSet)等。
  • 持久化支持:通过RDB快照和AOF日志保障数据安全。
  • 分布式能力:支持主从复制、哨兵模式、集群模式。
2. 典型应用场景
  • 缓存加速:减轻数据库压力,提升接口响应速度。
  • 分布式锁:解决多实例并发问题。
  • 会话共享:实现无状态服务的用户会话管理。
  • 实时排行榜:利用ZSet快速实现排序功能。

二、环境准备

1. 安装Redis
  • 本地安装 (推荐使用Docker):

    bash 复制代码
    # 拉取Redis镜像
    docker pull redis
    
    # 启动Redis容器
    docker run -d --name my-redis -p 6379:6379 redis
  • 直接安装 (Ubuntu):

    bash 复制代码
    sudo apt-get install redis-server
    sudo systemctl start redis
2. 创建Spring Boot项目

使用 Spring Initializr 创建项目,勾选以下依赖:

  • Spring Data Redis
  • Lombok(简化代码)

三、整合Redis的步骤

1. 添加依赖

检查pom.xml中是否包含Redis依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 配置Redis连接

application.properties中添加配置:

properties 复制代码
# Redis基础配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=  # 若无密码则留空

# 连接池配置(可选)
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=1000ms
3. 注入RedisTemplate

Spring Boot已自动配置RedisTemplate,可直接注入使用:

java 复制代码
@Autowired
private RedisTemplate<String, Object> redisTemplate;

四、Redis核心操作实战

1. 存储字符串(String)
java 复制代码
// 写入数据
redisTemplate.opsForValue().set("user:1:name", "John");

// 读取数据
String userName = (String) redisTemplate.opsForValue().get("user:1:name");
System.out.println("用户名:" + userName);  // 输出:John
2. 存储对象(Hash)
java 复制代码
// 定义用户对象
@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
}

// 存储Hash
User user = new User(1L, "Alice", 25);
redisTemplate.opsForHash().put("user:1", "info", user);

// 读取Hash
User cachedUser = (User) redisTemplate.opsForHash().get("user:1", "info");
System.out.println("用户年龄:" + cachedUser.getAge());  // 输出:25
3. 实现缓存注解

Spring Cache支持通过注解自动缓存数据:

java 复制代码
// 启用缓存
@SpringBootApplication
@EnableCaching
public class DemoApplication { ... }

// 在Service层使用缓存
@Service
public class UserService {
    @Cacheable(value = "userCache", key = "#id")
    public User getUserById(Long id) {
        // 模拟数据库查询
        System.out.println("查询数据库...");
        return new User(id, "Tom", 30);
    }
}
  • @Cacheable: 方法结果会被缓存,后续调用直接返回缓存值。
  • @CacheEvict: 删除缓存项。

五、高级功能扩展

1. 自定义序列化方式

默认的JDK序列化可读性差,建议改为JSON格式:

java 复制代码
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 使用Jackson2JsonRedisSerializer序列化
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(om);

        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        return template;
    }
}
2. 实现分布式锁
java 复制代码
public boolean tryLock(String lockKey, String requestId, long expireTime) {
    return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
}

public boolean releaseLock(String lockKey, String requestId) {
    String currentId = (String) redisTemplate.opsForValue().get(lockKey);
    if (requestId.equals(currentId)) {
        redisTemplate.delete(lockKey);
        return true;
    }
    return false;
}

六、常见问题与解决方案

1. 连接超时问题
  • 错误信息RedisConnectionFailureException: Unable to connect to Redis
  • 解决方案
    • 检查Redis服务是否启动。
    • 确认防火墙是否开放6379端口。
2. 序列化异常
  • 错误信息Could not read JSON: Unrecognized field
  • 解决方案
    • 确保实体类有无参构造方法。
    • 检查Jackson注解是否完整(如@JsonIgnore)。
3. 缓存穿透
  • 现象:频繁查询不存在的数据(如ID=-1)。

  • 解决 :使用布隆过滤器或缓存空值:

    java 复制代码
    @Cacheable(value = "userCache", key = "#id", unless = "#result == null")
    public User getUserById(Long id) { ... }
相关推荐
bing_15814 分钟前
JVM 类加载器在什么情况下会加载一个类?
java·jvm
kiss strong34 分钟前
Spring Boot向Vue发送消息通过WebSocket实现通信
vue.js·spring boot·websocket
冬天vs不冷1 小时前
EasyExcel导出自动回显中文,读取自动转换码值(基于全局转换器与自定义注解)
java·excel
阿里云云原生2 小时前
RAG 调优指南:Spring AI Alibaba 模块化 RAG 原理与使用
java·人工智能·spring
天上掉下来个程小白2 小时前
Redis-12.在Java中操作Redis-Spring Data Redis使用方式-操作字符串类型的数据
java·redis·spring·springboot·苍穹外卖
ん贤3 小时前
2023第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(真题&题解)(C++/Java题解)
java·c语言·数据结构·c++·算法·蓝桥杯
佚名涙4 小时前
go中锁的入门到进阶使用
开发语言·后端·golang
在京奋斗者5 小时前
spring boot自动装配原理
java·spring boot·spring
Amd7947 小时前
FastAPI中Pydantic异步分布式唯一性校验
redis·fastapi·分布式锁·多级缓存·pydantic·唯一性校验·异步校验
明天不下雨(牛客同名)7 小时前
为什么 ThreadLocalMap 的 key 是弱引用 value是强引用
java·jvm·算法