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 字符串)。

相关推荐
Coder_Boy_2 小时前
Java(Spring AI)传统项目智能化改造——商业化真实案例(含完整核心代码+落地指南)
java·人工智能·spring boot·spring·微服务
笑我归无处2 小时前
Springboot+mybatisplus配置多数据源+分页
spring boot·后端·mybatis
lizhongxuan3 小时前
AI 从工具调用到自主进化:SkillSMP 与 EvoMap
后端
暴力袋鼠哥3 小时前
基于 Spring Boot 3 + Vue 3 的农产品在线销售平台设计与实现
vue.js·spring boot·后端
canonical_entropy3 小时前
DDD 概念澄清:那些教程不会告诉你的事
后端·低代码·领域驱动设计
凌云拓界4 小时前
TypeWell全攻略(二):热力图渲染引擎,让键盘发光
前端·后端·python·计算机外设·交互·pyqt·数据可视化
李广坤5 小时前
Spring Boot Validation 使用手册
后端
柒.梧.5 小时前
吃透Spring Bean:生命周期、单例特性、作用域及扩展方式
java·后端·spring
嘻哈baby5 小时前
接口幂等性设计与实战:支付、下单、重试场景怎么搞?
后端