Redis 是一个键值(Key-Value)存储系统,它的值只能是基本数据类型(如 String, List, Hash, Set, Sorted Set 等),要将 Java 对象存入 Redis,我们必须先将对象进行序列化,将其转换成 Redis 可以识别的数据格式(通常是字节数组 byte[]),然后在读取时进行反序列化,将其从字节数组还原成 Java 对象。
下面我将详细介绍几种主流的实现方式,从简单到推荐,并附上完整示例。
核心步骤
无论使用哪种方法,基本流程都一样:
- 序列化:将 Java 对象转换为字节流。
- 存储:将字节流作为
Value存储到 Redis 中,Key通常是一个字符串。 - 读取:从 Redis 中通过
Key读取字节流。 - 反序列化:将字节流转换回原始的 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.properties 或 application.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 在同一个项目中共存。
- 手动序列化 只是为了让你理解底层原理,实际生产项目中应避免使用。
