SpringBoot连接Redis

SpringBoot连接Redis

  • SpringBoot连接Redis的方式
  • [RedisTemplate 与 StringRedisTemplate](#RedisTemplate 与 StringRedisTemplate)
  • [自定义 RedisTemplate](#自定义 RedisTemplate)

SpringBoot连接Redis的方式

引入依赖,在 pom.xml 中添加:

xml 复制代码
    <dependencies>
        <!-- SpringBoot 整合 Redis 核心依赖  -->
        <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>

        <!-- SpringBoot 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
  • spring-boot-starter-data-redis 是 Spring Boot 官方提供的 Redis 整合启动器,可自动完成 Redis 相关的核心配置,开箱即用。

    自动引入的关键组件:引入 Lettuce 客户端,自动配置开发中操作 Redis 的核心模板类 RedisTemplate 和 StringRedisTemplate,自动创建 RedisConnectionFactory(Redis 连接的核心工厂类),默认提供 JDK 序列化器。

    需要注意的是 Lettuce 的连接实例是线程安全的,多个线程可以共享同一个连接,无需为每个线程创建新连接,早期的 Jedis 客户端连接是线程不安全的,必须通过连接池为每个线程分配独立连接,否则会出现并发问题。

  • commons-pool2 连接池依赖,为 Redis 客户端提供连接池支持,是实现 Redis 连接复用的核心依赖。

    Redis 连接的创建与销毁开销很大,如果每次操作都新建连接,会严重影响性能,连接池可以提前创建一批连接,复用这些连接,大幅提升 Redis 操作的吞吐量。

  • spring-boot-starter-test 是 Spring Boot 官方提供的通用测试依赖,提供 Spring Boot 单元测试与集成测试所需的全套核心组件,可用于测试 Redis、数据库、接口等所有 Spring Boot 组件的逻辑正确性。

    自动引入的核心测试组件:Java 测试框架 JUnit、Spring 整合测试核心 Spring Test(Spring TestContext)、AssertJ 断言工具(简化测试结果校验)、Mockito 模拟工具(模拟外部依赖,降低测试环境依赖)。

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

yml 复制代码
spring:
    redis:
        # 基础连接信息
        host: 101.201.155.5    # Redis服务端IP
        port: 6379             # Redis端口
        password: ""           # Redis密码,无密码则留空
        database: 0            # 连接的Redis数据库编号,默认0号库
        timeout: 10000         # 连接超时时间,单位毫秒(默认10秒)
        # ==================== 以下根据客户端类型二选一配置 ====================
        # 【选项1】使用Lettuce客户端(SpringBoot默认,推荐)
        lettuce:
          pool:
            max-active: 8      # 连接池最大连接数(默认8)
            max-idle: 8        # 连接池最大空闲连接数(默认8)
            min-idle: 0        # 连接池最小空闲连接数(默认0)
            max-wait: -1ms     # 连接池最大等待时间,-1表示无限制(默认)
        
        # 【选项2】使用Jedis客户端(需先排除Lettuce依赖,再引入Jedis依赖)
        # jedis:
        #   pool:
        #     max-active: 8
        #     max-idle: 8
        #     min-idle: 0
        #     max-wait: -1ms

连接测试

java 复制代码
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.assertEquals;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testSetAndGet() {
        String key = "test:key";
        String value = "Hello Redis";

        // 写入
        redisTemplate.opsForValue().set(key, value);
        // 2. 读取
        Object result = redisTemplate.opsForValue().get(key);
        System.out.println("读取结果: " + result);

        // 3. 断言
        assertEquals(value, result);
    }
}

RedisTemplate 与 StringRedisTemplate

RedisTemplate

  • 序列化规则
    默认采用 JdkSerializationRedisSerializer(JDK 原生对象序列化器),不仅将对象的数据内容转换为字节数组,还会附加 Java 对象的元信息(如类全限定名、序列化版本号、类型标识等),其中 \xac\xed\x00\x05 是 JDK 序列化字节流的固定前缀,用于标识 JDK 序列化格式;
    需要注意的是被序列化的 Java 对象必须实现 java.io.Serializable 接口,否则会抛出 NotSerializableException 异常;
    序列化范围:默认对 Key、Value、HashKey、HashValue 均采用该序列化器。
  • 乱码现象
    在 redis-cli、Redis Desktop Manager 等客户端查看数据时出现的乱码,是解析规则不匹配造成的。
    Redis 客户端默认按 UTF-8 字符串规则解析字节流,但 JDK 序列化的字节流包含非 UTF-8 编码的前缀、元信息字节,这些字节无法被 UTF-8 正常解析,从而显示为乱码符号。Key 和 Value 都会出现该现象,并且与数据是否为中文无关。
  • 适用场景
    需要直接存储与读取完整 Java 实体对象,且无需在 Redis 客户端直接查看数据的场景;
    不推荐直接使用默认的 JDK 序列化器(可读性差、序列化体积大、版本兼容风险高),生产环境建议替换为 JSON 序列化器,既支持对象序列化,又能在客户端以 JSON 格式可读。

StringRedisTemplate

  • 序列化规则
    作为 RedisTemplate<String, String> 的子类,默认全维度采用 StringRedisSerializer(UTF-8 字符串序列化器),仅处理字符串类型数据,将 Java 字符串直接按 UTF-8 字符集转换为纯字节数组,无任何额外前缀和元信息;反序列化时,将字节数组按 UTF-8 直接转回字符串;
    序列化范围:Key、Value、HashKey、HashValue 均采用该序列化器(全维度字符串序列化)。
  • 无乱码特性
    序列化与反序列化规则与 Redis 原生客户端(redis-cli)、第三方可视化工具(如 Redis Desktop Manager)的默认解析规则(UTF-8)完全一致;与 Redis 原生命令(如 incr、keys、expire)完全兼容,可直接通过命令行操作 StringRedisTemplate 存储的 Key/Value。
  • 适用场景
    将 Java 对象先序列化为 JSON 字符串,再存储为字符串;
    存储令牌(token)、验证码、用户会话信息、配置项等纯字符串数据;
    分布式锁、计数器(incr/decr)、过期缓存控制等依赖 Redis 原生命令的场景;

StringRedisTemplate 可读性强、兼容原生命令、无序列化额外开销,是生产环境的首选模板类。

但若直接给 StringRedisTemplate 传 User 对象,编译阶段就会报错,因为 StringRedisTemplate 的 opsForValue().set() 方法要求第二个参数是 String 类型,编译不通过。

要 StringRedisTemplate 能处理 User 对象,必须要先把 Object 转成 String 格式,读取时再把 String 转回 Object,如下所示:

java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void testSaveUserRight() throws JsonProcessingException {
        // 创建 User 对象(Object 类型)
        User user = new User(1L, "张三", 25);

        // 手动把 User 对象转为 JSON 字符串
        String userJson = objectMapper.writeValueAsString(user);

        // 把 JSON 字符串传给 StringRedisTemplate
        stringRedisTemplate.opsForValue().set("user:1", userJson);

        // 读取时先取 JSON 字符串再手动转回 User 对象
        String savedUserJson = stringRedisTemplate.opsForValue().get("user:1");
        User savedUser = objectMapper.readValue(savedUserJson, User.class);

        System.out.println(savedUser.getName());
    }
}
java 复制代码
public class User {
    private Long id;
    private String name;
    private Integer age;

    public User() {
    }

    public User(Long id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

Jackson 反序列化 JSON 为 Java 对象的核心逻辑是:先创建一个空的 User 对象(需要依赖无参构造器),再通过 setter 方法把 JSON 里的字段值赋值给空对象的属性。

使用 RedisTemplate 直接存储与取出 Object 类型数据

java 复制代码
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testSaveUserWrong() {
        // 创建待存储的 User 对象
        User user = new User(1L, "张三", 25);

        // 存入 Redis
        String redisKey = "user:1";
        redisTemplate.opsForValue().set(redisKey, user);
        System.out.println("User 对象已存入 Redis,Key = " + redisKey);

        // 从 Redis 取出对象(需强制类型转换为 User)
        User savedUser = (User) redisTemplate.opsForValue().get(redisKey);
        System.out.println("从 Redis 取出 User 对象:" + savedUser);
    }
}

自定义 RedisTemplate

使用 RedisTemplate 直接存储与取出 Object 类型数据,但 RedisTemplate 会在 redis-cli、Redis Desktop Manager 等客户端查看数据时会出现乱码问题,下面进行编写自定义 RedisTemplate 可以避免这个问题,如下所示:

java 复制代码
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.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 1. 创建 RedisTemplate 实例
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 2. 绑定 Redis 连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 3. 配置序列化器(解决乱码,同时支持 Java 对象序列化)
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();   // 键序列化器
        GenericJackson2JsonRedisSerializer jacksonRedisSerializer = new GenericJackson2JsonRedisSerializer();  // 值序列化器

        // 4. 设置全局序列化规则
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jacksonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jacksonRedisSerializer);

        // 5. 初始化 RedisTemplate
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

自定义 RedisTemplate 是字符串序列化(Key/HashKey)与 JSON 序列化(Value/HashValue)的组合:

Key/HashKey 采用 StringRedisSerializer 按 UTF-8 规则明文序列化,Redis 中 Key/HashKey 均为纯字符串,无任何乱码;Value/HashValue 采用 GenericJackson2JsonRedisSerializer 序列化为标准 JSON 字符串,既解决了原生 RedisTemplate 因 JDK 二进制序列化导致的乱码问题,又保留了直接存储与读取 Java Object 的能力(无需手动转换 JSON 字符串)。

相关推荐
谭光志8 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..8 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects8 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰8 小时前
一些基础和问题解决
后端
陈随易9 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN9 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana9 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端
学渣超9 小时前
记一次分布式事务数据不一致的排查之旅:从超时到索引,层层剥茧
java·后端·架构
北冥you鱼9 小时前
Go 语言读取链上数据:从基础到实战
开发语言·后端·golang
程序员cxuan10 小时前
Claude Code 为了封禁中国用户,竟然在代码里下毒
人工智能·后端·程序员