杰瑞科技汇

redis java 存储对象

Redis 是一个键值(Key-Value)存储系统,它的值只能是基本数据类型(如 String, List, Hash, Set, Sorted Set 等),要将 Java 对象存入 Redis,我们必须先将对象进行序列化,将其转换成 Redis 可以识别的数据格式(通常是字节数组 byte[]),然后在读取时进行反序列化,将其从字节数组还原成 Java 对象。

下面我将详细介绍几种主流的实现方式,从简单到推荐,并附上完整示例。


核心步骤

无论使用哪种方法,基本流程都一样:

  1. 序列化:将 Java 对象转换为字节流。
  2. 存储:将字节流作为 Value 存储到 Redis 中,Key 通常是一个字符串。
  3. 读取:从 Redis 中通过 Key 读取字节流。
  4. 反序列化:将字节流转换回原始的 Java 对象。

手动序列化 (不推荐,但有助于理解)

这种方法最直观,你手动选择一个序列化工具(如 Java 原生的 Serializable 或第三方库如 Jackson/Gson),然后进行序列化和反序列化。

缺点

  • 代码冗余,每次存取都要写一遍序列化/反序列化代码。
  • 容易出错,需要处理 IOException 等异常。
  • 序列化后的字节流通常较大,且不跨语言。

示例 (使用 Java 原生 Serializable)

import java.io.*;
import java.util.Objects;
// 1. 你的 Java 对象必须实现 Serializable 接口
class User implements Serializable {
    private String id;
    private String name;
    private int age;
    // 构造方法、Getter/Setter、toString() 省略...
    // 为了演示,省略了 equals() 和 hashCode(),但实际开发中建议实现
    public User(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // ... 省略其他方法
}
public class ManualRedisObjectExample {
    public static void main(String[] args) {
        // 假设你已经有一个 JedisPool 或 Lettuce 连接
        // Jedis jedis = new Jedis("localhost", 6379);
        User user = new User("1001", "Alice", 30);
        // --- 存储对象 ---
        try {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(user);
            oos.flush();
            byte[] serializedUser = bos.toByteArray();
            // 存储到 Redis
            // jedis.set("user:1001".getBytes(), serializedUser);
            System.out.println("对象已序列化并准备存入Redis。");
            // --- 读取对象 ---
            // 从 Redis 读取
            // byte[] retrievedBytes = jedis.get("user:1001".getBytes());
            byte[] retrievedBytes = serializedUser; // 模拟从 Redis 读取
            if (retrievedBytes != null) {
                // 反序列化
                ByteArrayInputStream bis = new ByteArrayInputStream(retrievedBytes);
                ObjectInputStream ois = new ObjectInputStream(bis);
                User deserializedUser = (User) ois.readObject();
                System.out.println("成功从Redis反序列化对象: " + deserializedUser);
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // jedis.close();
        }
    }
}

使用 Spring Data Redis (推荐)

如果你正在使用 Spring Boot 框架,Spring Data Redis 是最佳选择,它极大地简化了 Redis 的操作,并提供了强大的序列化支持。

Spring Data Redis 内置了多种 RedisTemplate 实现,可以处理不同类型的序列化。

添加依赖 (pom.xml)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 如果使用 Lettuce 作为连接池(默认推荐),不需要额外依赖 -->
<!-- 如果使用 Jedis,需要添加 -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

配置序列化方式

application.propertiesapplication.yml 中配置 Redis 连接,并强烈建议自定义序列化方式,避免使用默认的 JdkSerializationRedisSerializer(因为它会产生非可读的序列化数据且不跨语言)。

application.yml 示例:

spring:
  redis:
    host: localhost
    port: 6379
    # lettuce:
    #   pool:
    #     max-active: 8
    #     max-idle: 8
    #     min-idle: 0

创建一个配置类来自定义 RedisTemplate

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 1. 创建 RedisTemplate 对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        // 2. 创建 Jackson2JsonRedisSerializer 序列化器
        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修饰的类,比如String,Integer会抛出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);
        // 3. 创建 StringRedisSerializer 序列化器 (用于 Key)
        StringRedisSerializer stringSerializer = new StringRedisSerializer();
        // 4. 设置 key 和 hashKey 的序列化器
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        // 5. 设置 value 和 hashValue 的序列化器
        template.setValueSerializer(jacksonSerializer);
        template.setHashValueSerializer(jacksonSerializer);
        // 6. 初始化 RedisTemplate
        template.afterPropertiesSet();
        return template;
    }
}

为什么推荐 Jackson2JsonRedisSerializer

  • 可读性强:序列化结果是 JSON 字符串,方便调试和直接查看 Redis 中的数据。
  • 跨语言:JSON 是通用的数据格式,可以被其他语言(如 Python, Go)轻松解析。
  • 兼容性好:与 Spring 生态无缝集成。

在 Service 中使用

你可以像操作 Map 一样操作 Redis 了。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    // 定义一个常量作为 Key 的前缀
    private static final String USER_KEY_PREFIX = "user:";
    public void saveUser(User user) {
        // 使用 opsForValue().set() 方法
        // Key: user:1001
        // Value: user 对象 (会被自动序列化为 JSON)
        redisTemplate.opsForValue().set(USER_KEY_PREFIX + user.getId(), user);
        System.out.println("用户 " + user.getName() + " 已存入 Redis。");
    }
    public User getUser(String id) {
        // 使用 opsForValue().get() 方法
        // Value 会被自动反序列化为 User 对象
        Object obj = redisTemplate.opsForValue().get(USER_KEY_PREFIX + id);
        if (obj instanceof User) {
            return (User) obj;
        }
        return null;
    }
    public void deleteUser(String id) {
        redisTemplate.delete(USER_KEY_PREFIX + id);
        System.out.println("用户 " + id + " 已从 Redis 中删除。");
    }
}

测试代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class RedisTestRunner implements CommandLineRunner {
    @Autowired
    private UserService userService;
    @Override
    public void run(String... args) throws Exception {
        // 创建一个用户
        User user = new User("1001", "Bob", 25);
        // 1. 保存用户
        userService.saveUser(user);
        // 2. 获取用户
        User retrievedUser = userService.getUser("1001");
        System.out.println("从 Redis 获取到的用户: " + retrievedUser);
        // 3. 删除用户
        userService.deleteUser("1001");
        // 4. 再次获取,应为 null
        User deletedUser = userService.getUser("1001");
        System.out.println("删除后再次获取: " + deletedUser);
    }
}

使用 Redisson (功能更强大的客户端)

Redisson 是一个在 Redis 基础上实现的驻留内存数据网格(In-Memory Data Grid),它提供了大量分布式的 Java 对象和服务,极大地扩展了 Redis 的功能。

如果你需要使用 Redis 的分布式锁、集合、Map 等高级数据结构,Redisson 是一个非常好的选择。

添加依赖 (pom.xml)

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.4</version> <!-- 使用最新版本 -->
</dependency>

配置

application.yml 配置与 Spring Data Redis 类似。

使用示例

Redisson 会自动处理序列化,你只需要注入 RBucket 对象即可。

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RedissonUserService {
    @Autowired
    private RedissonClient redissonClient;
    public void saveUser(User user) {
        // 获取一个 Bucket,Bucket 是 Redisson 提供的简单对象容器
        RBucket<User> bucket = redissonClient.getBucket("user:1002");
        bucket.set(user); // 直接设置对象,Redisson 会自动序列化
        System.out.println("用户 " + user.getName() + " 已通过 Redisson 存入。");
    }
    public User getUser(String id) {
        RBucket<User> bucket = redissonClient.getBucket("user:1002");
        return bucket.get(); // 直接获取对象,自动反序列化
    }
}

Redisson 的优点

  • 功能强大:提供了比标准 Redis 更丰富的数据结构(如 RMap, RSet, RLock 等)。
  • 使用简单:API 设计非常直观,像操作本地对象一样操作分布式对象。
  • 高性能:底层经过了高度优化。

总结与对比

特性 手动序列化 Spring Data Redis Redisson
易用性 差,代码繁琐 ,与 Spring 集成完美 ,API 设计直观
灵活性 高,可自由选择序列化器 高,可自定义 RedisTemplate 高,提供分布式对象服务
功能 仅基础存取 基础存取 + Spring 集成 非常丰富,锁、集合、Map 等
适用场景 学习原理,或项目极小 Spring/Spring Boot 项目首选 需要高级分布式功能的项目
序列化方式 自行选择(Jdk, Jackson等) 推荐 Jackson2JsonRedisSerializer 内置,可选择(默认 Jackson)

最终建议:

  • 如果你正在使用 Spring Boot,请毫不犹豫地选择 Spring Data Redis,并配置 Jackson2JsonRedisSerializer,这是最标准、最高效、最易于维护的方案。
  • 如果你的项目需要用到分布式锁、分布式集合等高级功能,或者你更喜欢面向对象的 API,Redisson 是你的不二之选,它也可以和 Spring Data Redis 在同一个项目中共存。
  • 手动序列化 只是为了让你理解底层原理,实际生产项目中应避免使用。
分享:
扫描分享到社交APP
上一篇
下一篇