Java 连接并操作 Redis 万字详解:从 Jedis 直连到 RedisTemplate 封装,5 种方式全解析
引言
在分布式系统和高并发场景中,Redis 作为高性能内存数据库的地位举足轻重。对于 Java 开发者而言,掌握 Redis 的连接与操作是进阶必备技能。然而,从基础的 Jedis 原生客户端到 Spring 封装的 RedisTemplate,不同连接方式的原理与适用场景常让初学者困惑。如何选择合适的连接方式?序列化配置背后的逻辑是什么?生产环境中又该如何优化?
本文从 Java 操作 Redis 的核心需求出发,通过完整代码示例与逐行解析,系统讲解 Jedis 直接连接、连接池、RedisTemplate 及 StringRedisTemplate 的使用方法,深入剖析连接原理、序列化机制与性能优化策略。无论你是刚接触 Redis 的小白,还是需要规范项目实践的开发者,都能从代码细节与原理分析中获得启发,掌握从基础连接到高级应用的全流程实战技巧。
1. Redis 基础概念与 Java 生态概览
1.1 Redis 是什么?
Redis(Remote Dictionary Server)是一个基于内存的高性能键值对存储系统,具有以下核心特性:
-
数据结构丰富:支持 String、Hash、List、Set、Sorted Set 等 8 种数据结构
-
内存级性能:读写速度可达 10 万 + 次 / 秒(String 类型)
-
持久化支持:提供 RDB(快照)和 AOF(日志)两种持久化方式
-
集群能力:支持主从复制、哨兵模式、Cluster 集群
-
多语言支持:提供 Java、Python、Node.js 等多语言客户端
在 Java 生态中,主流的 Redis 客户端包括:
-
Jedis:官方提供的原生 Java 客户端,支持同步阻塞式 IO
-
Lettuce:基于 Netty 的异步非阻塞客户端,支持响应式编程
-
Spring Data Redis:Spring 封装的高层抽象,支持 Jedis/Lettuce 作为底层连接
1.2 Java 操作 Redis 的核心场景
-
缓存系统:降低数据库压力(如商品详情页缓存)
-
分布式会话:解决集群环境下的 Session 共享问题
-
计数器:实现点赞计数、接口限流等功能(利用 INCR 命令)
-
消息队列:基于 List 的 LPUSH/RPOP 实现简单队列
-
分布式锁:通过 SETNX 命令实现分布式锁机制
2.Jedis 原生客户端:从直接连接到连接池
2.0 Maven依赖
redis.clients jedis 3.7.0
2.1 Jedis 直接连接(非池化方式)
2.1.1 核心代码解析
@Slf4j @SpringBootTest public class JedisDirect { private Jedis jedis; @BeforeEach public void setUp(){ //建立连接 jedis = new Jedis("x.x.x.x",6379); //设置密码 jedis.auth("xxxx"); //选择库 jedis.select(0); } @Test public void testString(){ jedis.set("namePool","zhangsanPool"); String value = jedis.get("name"); log.info("value:"+value); } @Test public void testHash(){ jedis.hset("user:2","name","lisiPool"); jedis.hset("user:2","age","21"); Map map = jedis.hgetAll("user:1"); log.info("map:"+ map.toString()); } @AfterEach public void tearDown(){ if(jedis != null){ jedis.close(); } } }
代码的执行结果:
结果1:
结果2:
2.1.2 核心类与对象
-
Jedis:核心客户端类,封装了所有 Redis 命令
-
构造方法:Jedis(String host, int port) 初始化连接
-
常用方法:
-
set(String key, String value):存储字符串
-
get(String key):获取字符串
-
hset(String key, String field, String value):存储 Hash 字段
-
hgetAll(String key):获取 Hash 所有字段
-
@BeforeEach/@AfterEach:JUnit5 生命周期注解,分别用于初始化和销毁资源
2.1.3 原理分析
- 连接过程:
-
创建 Jedis 实例时建立 TCP 连接(三次握手)
-
通过 auth 命令进行密码验证(如果配置了密码)
-
select 命令选择操作的数据库(默认 0 号库)
- 命令执行:
-
客户端将命令序列化为字节流发送到 Redis 服务器
-
服务器执行命令后返回结果,客户端解析响应
2.1.4 优缺点
-
优点:简单直观,适合学习和小规模测试
-
缺点:
-
每次测试都创建新连接,性能低下(TCP 连接创建开销大)
-
并发场景下可能导致连接风暴
-
没有连接复用机制,资源利用率低
2.2 Jedis 连接池(池化连接)
2.2.1 连接池配置类
public class JedisConnectionFactory { private static final JedisPool jedisPool; static{ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); //最大连接 jedisPoolConfig.setMaxTotal(10); //最大空闲连接 jedisPoolConfig.setMaxIdle(10); //最小空闲连接 jedisPoolConfig.setMinIdle(5); //设置最长等待时间 jedisPoolConfig.setMaxWaitMillis(200); jedisPool = new JedisPool(jedisPoolConfig,"x.x.x.x",6379, 1000,"xxxx"); } //获取jedis对象 public static Jedis getJedis(){ return jedisPool.getResource(); } }
说明:
-
JedisPool:连接池核心类,管理连接的创建和回收
- getResource():从连接池获取可用连接(可能从空闲队列获取或新建)
-
JedisPoolConfig:连接池配置类,常用参数:
-
maxTotal:最大连接数(控制并发量)
-
maxIdle:最大空闲连接数(避免空闲连接过多)
-
minIdle:最小空闲连接数(保证基础可用连接)
-
maxWaitMillis:获取连接超时时间(避免无限阻塞)
2.2.2 连接池工作原理
- 初始化阶段:
- 启动时创建minIdle数量的空闲连接
- 获取连接:
-
优先从空闲队列中获取连接
-
若空闲队列为空,且当前连接数小于maxTotal,则新建连接
-
若连接数已达maxTotal,则等待maxWaitMillis时间
- 归还连接:
-
调用close()方法时,连接不会真正关闭,而是放回空闲队列
-
空闲连接数超过maxIdle时,多余连接会被销毁
2.2.3 使用示例
@Slf4j @SpringBootTest public class JedisPool { private Jedis jedis; @BeforeEach public void setUp(){ //建立连接 jedis = JedisConnectionFactory.getJedis(); //设置密码 jedis.auth("dhj20030916."); //选择库 jedis.select(0); } @Test public void testString(){ jedis.set("name","zhangsan"); String value = jedis.get("name"); log.info("value:"+value); } @Test public void testHash(){ jedis.hset("user:1","name","lisi"); jedis.hset("user:1","age","21"); Map map = jedis.hgetAll("user:1"); log.info("map:"+ map.toString()); } @AfterEach public void tearDown(){ if(jedis != null){ jedis.close(); } } }
运行结果:
结果1:
结果2:
2.2.5 优势对比
特性 直接连接 连接池方式 连接创建 每次新建 复用已有连接 并发支持 差 好(控制连接数) 资源利用率 低 高 性能 差(连接开销) 好(减少握手) 适用场景 单线程测试 高并发生产环境 3. Spring Data Redis:高层抽象与模板化操作
3.1 核心依赖与配置
3.1.1 Maven 依赖
org.springframework.boot spring-boot-starter-data-redis
3.1.2 YAML 配置
spring: redis: host: x.x.x.x port: 6379 password: xxxx lettuce: pool: max-active: 10 #最大连接 max-idle: 10 #最大空闲连接 min-idle: 0 #最小空闲连接 max-wait: 100 #连接等待时间
3.2 RedisTemplate 核心类解析
3.2.1 基础操作示例
@SpringBootTest @Slf4j public class RedisTem { @Autowired private RedisTemplate redisTemplate; @Test public void test(){ //插入一条String类型的数据 redisTemplate.opsForValue().set("nameTem","赵六"); Object s = redisTemplate.opsForValue().get("nameTem"); log.info("nameTem:"+ s); } }
运行结果:
3.2.2 核心类结构
-
RedisTemplate:
-
泛型参数: 分别表示键和值的类型
-
核心方法:
-
opsForValue():获取字符串操作对象(对应 String 类型)
-
opsForHash():获取 Hash 操作对象(对应 Hash 类型)
-
opsForList():获取列表操作对象(对应 List 类型)
-
opsForSet():获取集合操作对象(对应 Set 类型)
-
opsForZSet():获取有序集合操作对象(对应 Sorted Set 类型)
-
RedisConnectionFactory:
-
连接工厂接口,支持 Jedis/Lettuce 等多种实现
-
Spring 自动根据依赖加载对应的实现(如引入 jedis 依赖则使用 JedisConnectionFactory)
3.3 序列化机制详解
3.3.1 默认序列化问题
-
Spring Data Redis 默认使用JdkSerializationRedisSerializer:
- 序列化后数据冗余(包含类名、版本号等信息)
- 依赖类必须实现Serializable接口
- 跨语言不兼容(如 Python 无法解析 JDK 序列化数据)
3.3.2 JSON 序列化配置
@Configuration public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { // 创建redisTemplate对象 RedisTemplate redisTemplate = new RedisTemplate(); //设置连接工厂 redisTemplate.setConnectionFactory(connectionFactory); // 创建json序列化工具 GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); //设置Key的序列化 redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string()); //设置value的序列化 redisTemplate.setValueSerializer(jsonRedisSerializer); redisTemplate.setHashValueSerializer(jsonRedisSerializer); return redisTemplate; } }
3.3.3 序列化流程
- 存储数据:
-
值对象(如 User 对象)通过 JSON 序列化工具转为 JSON 字符串
-
键和 Hash 键通过 String 序列化转为字节数组
- 读取数据:
-
从 Redis 获取字节数组后,键反序列化为 String
-
值反序列化为对应的对象(通过 Jackson 的类型推断)
3.4 对象存储实战(序列化配置后)
3.4.1 User 实体类
@Data public class User { private Integer id; private String name; private Integer age; }
3.4.2 测试代码
@SpringBootTest @Slf4j public class RedisTemSer { @Autowired private RedisTemplate redisTemplate; @Test public void testString(){ redisTemplate.opsForValue().set("nameTemSer","test"); String value = (String)redisTemplate.opsForValue().get("nameTemSer"); log.info("value"+ value); } @Test public void testHash(){ redisTemplate.opsForHash().put("user:3","name","hash"); redisTemplate.opsForHash().put("user:3","age","22"); Map map = (Map)redisTemplate.opsForHash().entries("user:3"); log.info("map"+ map); } @Test public void testObject(){ User user = new User(); user.setId(1); user.setName("object"); user.setAge(20); redisTemplate.opsForValue().set("User",user); Object object = redisTemplate.opsForValue().get("User"); log.info("object"+ object); } }
运行结果:
结果1:
结果2:
结果3:
3.4.3 关键细节
-
类型转换:
- opsForValue().set(key, value) 支持任意对象,内部自动序列化
- opsForValue().get(key) 返回 Object 类型,需手动强转(依赖序列化配置)
-
Hash 操作:
- opsForHash().put(key, field, value) 存储 Hash 字段,value 自动序列化
- entries() 方法返回 Map,字段值已反序列化
4. StringRedisTemplate:专注字符串场景
4.1 基本概念
-
StringRedisTemplate 是 RedisTemplate 的子类
-
默认配置:
-
键序列化:StringRedisSerializer(等同于RedisSerializer.string())
-
值序列化:StringRedisSerializer(直接存储字符串)
4.2 对象操作实战
4.2.1 测试代码
@Slf4j @SpringBootTest public class StringRedisTem { @Autowired private StringRedisTemplate stringRedisTemplate; private static final ObjectMapper mapper = new ObjectMapper(); @Test public void testObject() throws JsonProcessingException { User user = new User(); user.setId(2); user.setName("StringRedisTem"); user.setAge(20); // 手动序列化value String json = mapper.writeValueAsString(user); stringRedisTemplate.opsForValue().set("UserRedis", json); // 获取数据 String val = stringRedisTemplate.opsForValue().get("UserRedis"); // 手动反序列化 User userValue = mapper.readValue(val,User.class); log.info(userValue.toString()); } }
运行结果:
4.2.2 核心步骤解析
- 序列化:
-
使用 Jackson 的ObjectMapper将 User 对象转为 JSON 字符串
-
解决StringRedisTemplate只能存储字符串的限制
- 存储与获取:
-
opsForValue().set(key, value) 直接存储字符串
-
opsForValue().get(key) 直接获取字符串
- 反序列化:
-
将获取的 JSON 字符串转为 User 对象
-
需要处理可能的JsonProcessingException异常
4.3 与 RedisTemplate 的对比
特性 RedisTemplate StringRedisTemplate 泛型参数 任意类型 序列化 支持自定义序列化 固定 String 序列化 对象操作 自动序列化 / 反序列化 需手动序列化 / 反序列化 键类型 任意类型(需序列化) 只能是 String 类型 适用场景 复杂数据类型(对象、Hash 等) 纯字符串场景(如缓存文本) 5. 连接方式深度对比与选型建议
5.1 技术维度对比
维度 Jedis 直接连接 Jedis 连接池 RedisTemplate StringRedisTemplate 连接管理 手动创建 连接池管理 框架管理 框架管理 序列化支持 无(需手动) 无 支持自定义 仅 String 序列化 Spring 集成 弱 弱 强(自动装配) 强(自动装配) 学习成本 低 中 中 低 并发性能 差 优 优 优 5.2 场景化选型建议
5.2.1 学习阶段
-
推荐使用 Jedis 直接连接:
-
代码简单,便于理解 Redis 基本操作
-
适合单个命令测试(如 GET/SET/HSET 等)
5.2.2 小型项目(非 Spring)
-
推荐 Jedis 连接池:
-
避免频繁创建连接,提升性能
-
手动管理连接,适合轻量级项目
5.2.3 Spring Boot 项目
-
优先使用 RedisTemplate:
-
与 Spring 生态无缝集成(依赖注入、配置管理)
-
支持复杂数据类型和自定义序列化
-
推荐配置 JSON 序列化,兼容对象存储
5.2.4 纯字符串场景
-
使用 StringRedisTemplate:
- 简化字符串操作(避免泛型转换)
- 性能略优(减少序列化层开销)
5.3 生产环境最佳实践
- 连接池配置:
-
maxTotal设置为系统并发量的 1.5-2 倍
-
maxWaitMillis不超过 200ms(避免过长阻塞)
-
minIdle设置为 5-10(保证基础连接可用性)
- 序列化选择:
-
统一使用 JSON 序列化(GenericJackson2JsonRedisSerializer)
-
键使用 String 序列化(保证可读性和可维护性)
- 异常处理:
-
添加try-catch-finally块,确保连接归还
-
处理JedisConnectionException等网络异常
- 监控与调优:
-
监控连接池的空闲连接数、活跃连接数
-
使用 Redis 的INFO connection命令查看服务器连接状态
6. 常见问题与解决方案
6.1 连接失败问题
现象:
- 抛出JedisConnectionException: ``java.net``.ConnectException: Connection refused
可能原因:
-
Redis 服务器未启动
-
IP 地址或端口错误(检查配置中的 host 和 port)
-
防火墙阻止连接(需开放 6379 端口)
-
Redis 密码错误(auth 命令失败)
解决方案:
-
确保 Redis 服务器正常运行(redis-cli ping检查连通性)
-
核对配置中的连接参数(IP、端口、密码)
-
检查服务器防火墙设置(如 Linux 的firewall-cmd)
6.2 数据乱码问题
现象:
- Redis 存储的字符串在 Java 中获取时出现乱码
可能原因:
-
未正确设置字符编码(Jedis 默认使用 UTF-8)
-
序列化方式不匹配(如 RedisTemplate 使用 JDK 序列化,手动使用字符串读取)
解决方案:
- Jedis 中指定编码:
jedis.get("key", StandardCharsets.UTF\_8); // 显式指定编码
- RedisTemplate 统一使用 String 序列化:
template.setKeySerializer(RedisSerializer.string());
6.3 对象反序列化失败
现象:
- 从 Redis 获取对象时抛出ClassNotFoundException
可能原因:
-
使用 JDK 序列化时,类路径不一致(如部署环境类缺失)
-
JSON 序列化时,对象缺少无参构造函数(Jackson 需要)
解决方案:
- 改用 JSON 序列化(避免类路径问题)
- 确保实体类包含无参构造函数(Lombok 的@Data默认生成)
7. 扩展知识:异步客户端 Lettuce
7.1 Lettuce 简介
-
基于 Netty 的异步非阻塞客户端
-
支持响应式编程(Reactor 模式)
-
适合高并发、高吞吐量场景
7.2 核心差异
特性 Jedis Lettuce IO 模型 同步阻塞 异步非阻塞 连接方式 每个线程一个连接 单个连接处理多个请求 线程安全 非线程安全 线程安全 适用场景 简单同步场景 异步 / 反应式场景 7.3 配置示例
spring: redis: host: 1.94.22.150 port: 6379 password: dhj20030916. lettuce: pool: max-active: 10 #最大连接 max-idle: 10 #最大空闲连接 min-idle: 0 #最小空闲连接 max-wait: 100 #连接等待时间
8. 总结:从入门到实战的成长路径
8.1 学习阶段建议
-
基础操作:掌握 Jedis 直接连接,理解 Redis 基本命令(SET/GET/HSET 等)
-
性能优化:学习连接池原理,掌握 JedisPool 配置与使用
-
框架集成:深入 Spring Data Redis,学会配置 RedisTemplate 和序列化
-
实战提升:在项目中应用缓存、分布式锁等场景,处理实际问题
8.2 核心知识图谱
8.3 结语
通过本文的系统学习,读者应能熟练掌握 Java 操作 Redis 的主流方式,理解不同连接方式的适用场景和底层原理,并能够在实际项目中根据需求选择合适的技术方案。记住,实践是最好的老师,建议通过实际项目练习加深理解,遇到问题时结合官方文档和源码进行分析,逐步提升 Redis 开发与运维能力。
-
-
-
-
- 抛出JedisConnectionException: ``java.net``.ConnectException: Connection refused
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-