Java連接并操作Redis超詳細教程
引言
在分布式系統(tǒng)和高并發(fā)場景中,Redis 作為高性能內(nèi)存數(shù)據(jù)庫的地位舉足輕重。對于 Java 開發(fā)者而言,掌握 Redis 的連接與操作是進階必備技能。然而,從基礎(chǔ)的 Jedis 原生客戶端到 Spring 封裝的 RedisTemplate,不同連接方式的原理與適用場景常讓初學(xué)者困惑。如何選擇合適的連接方式?序列化配置背后的邏輯是什么?生產(chǎn)環(huán)境中又該如何優(yōu)化?
本文從 Java 操作 Redis 的核心需求出發(fā),通過完整代碼示例與逐行解析,系統(tǒng)講解 Jedis 直接連接、連接池、RedisTemplate 及 StringRedisTemplate 的使用方法,深入剖析連接原理、序列化機制與性能優(yōu)化策略。無論你是剛接觸 Redis 的小白,還是需要規(guī)范項目實踐的開發(fā)者,都能從代碼細節(jié)與原理分析中獲得啟發(fā),掌握從基礎(chǔ)連接到高級應(yīng)用的全流程實戰(zhàn)技巧。
1. Redis 基礎(chǔ)概念與 Java 生態(tài)概覽
1.1 Redis 是什么?
Redis(Remote Dictionary Server)是一個基于內(nèi)存的高性能鍵值對存儲系統(tǒng),具有以下核心特性:
- 數(shù)據(jù)結(jié)構(gòu)豐富:支持 String、Hash、List、Set、Sorted Set 等 8 種數(shù)據(jù)結(jié)構(gòu)
- 內(nèi)存級性能:讀寫速度可達 10 萬 + 次 / 秒(String 類型)
- 持久化支持:提供 RDB(快照)和 AOF(日志)兩種持久化方式
- 集群能力:支持主從復(fù)制、哨兵模式、Cluster 集群
- 多語言支持:提供 Java、Python、Node.js 等多語言客戶端
在 Java 生態(tài)中,主流的 Redis 客戶端包括:
- Jedis:官方提供的原生 Java 客戶端,支持同步阻塞式 IO
- Lettuce:基于 Netty 的異步非阻塞客戶端,支持響應(yīng)式編程
- Spring Data Redis:Spring 封裝的高層抽象,支持 Jedis/Lettuce 作為底層連接
1.2 Java 操作 Redis 的核心場景
- 緩存系統(tǒng):降低數(shù)據(jù)庫壓力(如商品詳情頁緩存)
- 分布式會話:解決集群環(huán)境下的 Session 共享問題
- 計數(shù)器:實現(xiàn)點贊計數(shù)、接口限流等功能(利用 INCR 命令)
- 消息隊列:基于 List 的 LPUSH/RPOP 實現(xiàn)簡單隊列
- 分布式鎖:通過 SETNX 命令實現(xiàn)分布式鎖機制
2.Jedis 原生客戶端:從直接連接到連接池
2.0 Maven依賴
<!-- Jedis--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> </dependency>
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); //設(shè)置密碼 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<String,String> map = jedis.hgetAll("user:1"); log.info("map:"+ map.toString()); } @AfterEach public void tearDown(){ if(jedis != null){ jedis.close(); } } }
代碼的執(zhí)行結(jié)果:
結(jié)果1:
結(jié)果2:
2.1.2 核心類與對象
Jedis:核心客戶端類,封裝了所有 Redis 命令
構(gòu)造方法: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 原理分析
連接過程:
- 創(chuàng)建 Jedis 實例時建立 TCP 連接(三次握手)
- 通過 auth 命令進行密碼驗證(如果配置了密碼)
- select 命令選擇操作的數(shù)據(jù)庫(默認 0 號庫)
命令執(zhí)行:
- 客戶端將命令序列化為字節(jié)流發(fā)送到 Redis 服務(wù)器
- 服務(wù)器執(zhí)行命令后返回結(jié)果,客戶端解析響應(yīng)
2.1.4 優(yōu)缺點
- 優(yōu)點:簡單直觀,適合學(xué)習(xí)和小規(guī)模測試
- 缺點:
- 每次測試都創(chuàng)建新連接,性能低下(TCP 連接創(chuàng)建開銷大)
- 并發(fā)場景下可能導(dǎo)致連接風(fēng)暴
- 沒有連接復(fù)用機制,資源利用率低
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); //設(shè)置最長等待時間 jedisPoolConfig.setMaxWaitMillis(200); jedisPool = new JedisPool(jedisPoolConfig,"x.x.x.x",6379, 1000,"xxxx"); } //獲取jedis對象 public static Jedis getJedis(){ return jedisPool.getResource(); } }
說明:
JedisPool:連接池核心類,管理連接的創(chuàng)建和回收
getResource()
:從連接池獲取可用連接(可能從空閑隊列獲取或新建)
JedisPoolConfig:連接池配置類,常用參數(shù):
maxTotal
:最大連接數(shù)(控制并發(fā)量)maxIdle
:最大空閑連接數(shù)(避免空閑連接過多)minIdle
:最小空閑連接數(shù)(保證基礎(chǔ)可用連接)
maxWaitMillis
:獲取連接超時時間(避免無限阻塞)
2.2.2 連接池工作原理
初始化階段:
- 啟動時創(chuàng)建
minIdle
數(shù)量的空閑連接
獲取連接:
- 優(yōu)先從空閑隊列中獲取連接
- 若空閑隊列為空,且當(dāng)前連接數(shù)小于
maxTotal
,則新建連接 - 若連接數(shù)已達
maxTotal
,則等待maxWaitMillis
時間
歸還連接:
- 調(diào)用
close()
方法時,連接不會真正關(guān)閉,而是放回空閑隊列 - 空閑連接數(shù)超過
maxIdle
時,多余連接會被銷毀
2.2.3 使用示例
@Slf4j @SpringBootTest public class JedisPool { private Jedis jedis; @BeforeEach public void setUp(){ //建立連接 jedis = JedisConnectionFactory.getJedis(); //設(shè)置密碼 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<String,String> map = jedis.hgetAll("user:1"); log.info("map:"+ map.toString()); } @AfterEach public void tearDown(){ if(jedis != null){ jedis.close(); } } }
運行結(jié)果:
結(jié)果1:
結(jié)果2:
2.2.4 優(yōu)勢對比
特性 | 直接連接 | 連接池方式 |
---|---|---|
連接創(chuàng)建 | 每次新建 | 復(fù)用已有連接 |
并發(fā)支持 | 差 | 好(控制連接數(shù)) |
資源利用率 | 低 | 高 |
性能 | 差(連接開銷) | 好(減少握手) |
適用場景 | 單線程測試 | 高并發(fā)生產(chǎn)環(huán)境 |
3. Spring Data Redis:高層抽象與模板化操作
3.1 核心依賴與配置
3.1.1 Maven 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
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 基礎(chǔ)操作示例
@SpringBootTest @Slf4j public class RedisTem { @Autowired private RedisTemplate redisTemplate; @Test public void test(){ //插入一條String類型的數(shù)據(jù) redisTemplate.opsForValue().set("nameTem","趙六"); Object s = redisTemplate.opsForValue().get("nameTem"); log.info("nameTem:"+ s); } }
運行結(jié)果:
3.2.2 核心類結(jié)構(gòu)
RedisTemplate:
泛型參數(shù):<K, V>
分別表示鍵和值的類型
核心方法:
opsForValue()
:獲取字符串操作對象(對應(yīng) String 類型)opsForHash()
:獲取 Hash 操作對象(對應(yīng) Hash 類型)opsForList()
:獲取列表操作對象(對應(yīng) List 類型)opsForSet()
:獲取集合操作對象(對應(yīng) Set 類型)opsForZSet()
:獲取有序集合操作對象(對應(yīng) Sorted Set 類型)
RedisConnectionFactory:
- 連接工廠接口,支持 Jedis/Lettuce 等多種實現(xiàn)
- Spring 自動根據(jù)依賴加載對應(yīng)的實現(xiàn)(如引入 jedis 依賴則使用 JedisConnectionFactory)
3.3 序列化機制詳解
3.3.1 默認序列化問題
Spring Data Redis 默認使用JdkSerializationRedisSerializer
:
- 序列化后數(shù)據(jù)冗余(包含類名、版本號等信息)
- 依賴類必須實現(xiàn)
Serializable
接口 - 跨語言不兼容(如 Python 無法解析 JDK 序列化數(shù)據(jù))
3.3.2 JSON 序列化配置
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { // 創(chuàng)建redisTemplate對象 RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); //設(shè)置連接工廠 redisTemplate.setConnectionFactory(connectionFactory); // 創(chuàng)建json序列化工具 GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); //設(shè)置Key的序列化 redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string()); //設(shè)置value的序列化 redisTemplate.setValueSerializer(jsonRedisSerializer); redisTemplate.setHashValueSerializer(jsonRedisSerializer); return redisTemplate; } }
3.3.3 序列化流程
存儲數(shù)據(jù):
- 值對象(如 User 對象)通過 JSON 序列化工具轉(zhuǎn)為 JSON 字符串
- 鍵和 Hash 鍵通過 String 序列化轉(zhuǎn)為字節(jié)數(shù)組
讀取數(shù)據(jù):
- 從 Redis 獲取字節(jié)數(shù)組后,鍵反序列化為 String
- 值反序列化為對應(yīng)的對象(通過 Jackson 的類型推斷)
3.4 對象存儲實戰(zhàn)(序列化配置后)
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<String,Object> map = (Map<String,Object>)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); } }
運行結(jié)果:
結(jié)果1:
結(jié)果2:
結(jié)果3:
3.4.3 關(guān)鍵細節(jié)
類型轉(zhuǎn)換:
opsForValue().set(key, value)
支持任意對象,內(nèi)部自動序列化opsForValue().get(key)
返回 Object 類型,需手動強轉(zhuǎn)(依賴序列化配置)
Hash 操作:
opsForHash().put(key, field, value)
存儲 Hash 字段,value 自動序列化entries()
方法返回 Map<String, Object>,字段值已反序列化
4. StringRedisTemplate:專注字符串場景
4.1 基本概念
StringRedisTemplate 是 RedisTemplate<String, String>
的子類
默認配置:
- 鍵序列化:
StringRedisSerializer
(等同于RedisSerializer.string()
) - 值序列化:
StringRedisSerializer
(直接存儲字符串)
4.2 對象操作實戰(zhàn)
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); // 獲取數(shù)據(jù) String val = stringRedisTemplate.opsForValue().get("UserRedis"); // 手動反序列化 User userValue = mapper.readValue(val,User.class); log.info(userValue.toString()); } }
運行結(jié)果:
4.2.2 核心步驟解析
序列化:
- 使用 Jackson 的
ObjectMapper
將 User 對象轉(zhuǎn)為 JSON 字符串 - 解決
StringRedisTemplate
只能存儲字符串的限制
存儲與獲取:
opsForValue().set(key, value)
直接存儲字符串opsForValue().get(key)
直接獲取字符串
反序列化:
- 將獲取的 JSON 字符串轉(zhuǎn)為 User 對象
- 需要處理可能的
JsonProcessingException
異常
4.3 與 RedisTemplate 的對比
特性 | RedisTemplate | StringRedisTemplate |
---|---|---|
泛型參數(shù) | <K, V> 任意類型 | <String, String> |
序列化 | 支持自定義序列化 | 固定 String 序列化 |
對象操作 | 自動序列化 / 反序列化 | 需手動序列化 / 反序列化 |
鍵類型 | 任意類型(需序列化) | 只能是 String 類型 |
適用場景 | 復(fù)雜數(shù)據(jù)類型(對象、Hash 等) | 純字符串場景(如緩存文本) |
5. 連接方式深度對比與選型建議
5.1 技術(shù)維度對比
維度 | Jedis 直接連接 | Jedis 連接池 | RedisTemplate | StringRedisTemplate |
---|---|---|---|---|
連接管理 | 手動創(chuàng)建 | 連接池管理 | 框架管理 | 框架管理 |
序列化支持 | 無(需手動) | 無 | 支持自定義 | 僅 String 序列化 |
Spring 集成 | 弱 | 弱 | 強(自動裝配) | 強(自動裝配) |
學(xué)習(xí)成本 | 低 | 中 | 中 | 低 |
并發(fā)性能 | 差 | 優(yōu) | 優(yōu) | 優(yōu) |
5.2 場景化選型建議
5.2.1 學(xué)習(xí)階段
推薦使用 Jedis 直接連接:
- 代碼簡單,便于理解 Redis 基本操作
- 適合單個命令測試(如 GET/SET/HSET 等)
5.2.2 小型項目(非 Spring)
推薦 Jedis 連接池:
- 避免頻繁創(chuàng)建連接,提升性能
- 手動管理連接,適合輕量級項目
5.2.3 Spring Boot 項目
優(yōu)先使用 RedisTemplate:
- 與 Spring 生態(tài)無縫集成(依賴注入、配置管理)
- 支持復(fù)雜數(shù)據(jù)類型和自定義序列化
- 推薦配置 JSON 序列化,兼容對象存儲
5.2.4 純字符串場景
使用 StringRedisTemplate:
- 簡化字符串操作(避免泛型轉(zhuǎn)換)
- 性能略優(yōu)(減少序列化層開銷)
5.3 生產(chǎn)環(huán)境最佳實踐
連接池配置:
maxTotal
設(shè)置為系統(tǒng)并發(fā)量的 1.5-2 倍maxWaitMillis
不超過 200ms(避免過長阻塞)minIdle
設(shè)置為 5-10(保證基礎(chǔ)連接可用性)
序列化選擇:
- 統(tǒng)一使用 JSON 序列化(
GenericJackson2JsonRedisSerializer
) - 鍵使用 String 序列化(保證可讀性和可維護性)
異常處理:
- 添加
try-catch-finally
塊,確保連接歸還 - 處理
JedisConnectionException
等網(wǎng)絡(luò)異常
監(jiān)控與調(diào)優(yōu):
- 監(jiān)控連接池的空閑連接數(shù)、活躍連接數(shù)
- 使用 Redis 的
INFO connection
命令查看服務(wù)器連接狀態(tài)
6. 常見問題與解決方案
6.1 連接失敗問題
現(xiàn)象:
- 拋出
JedisConnectionException: ``java.net``.ConnectException: Connection refused
可能原因:
- Redis 服務(wù)器未啟動
- IP 地址或端口錯誤(檢查配置中的 host 和 port)
- 防火墻阻止連接(需開放 6379 端口)
- Redis 密碼錯誤(auth 命令失敗)
解決方案:
- 確保 Redis 服務(wù)器正常運行(
redis-cli ping
檢查連通性) - 核對配置中的連接參數(shù)(IP、端口、密碼)
- 檢查服務(wù)器防火墻設(shè)置(如 Linux 的
firewall-cmd
)
6.2 數(shù)據(jù)亂碼問題
現(xiàn)象:
Redis 存儲的字符串在 Java 中獲取時出現(xiàn)亂碼
可能原因:
- 未正確設(shè)置字符編碼(Jedis 默認使用 UTF-8)
- 序列化方式不匹配(如 RedisTemplate 使用 JDK 序列化,手動使用字符串讀?。?/li>
解決方案:
Jedis 中指定編碼:
jedis.get("key", StandardCharsets.UTF\_8); // 顯式指定編碼
RedisTemplate 統(tǒng)一使用 String 序列化:
template.setKeySerializer(RedisSerializer.string());
6.3 對象反序列化失敗
現(xiàn)象:
- 從 Redis 獲取對象時拋出
ClassNotFoundException
可能原因:
- 使用 JDK 序列化時,類路徑不一致(如部署環(huán)境類缺失)
- JSON 序列化時,對象缺少無參構(gòu)造函數(shù)(Jackson 需要)
解決方案:
- 改用 JSON 序列化(避免類路徑問題)
- 確保實體類包含無參構(gòu)造函數(shù)(Lombok 的
@Data
默認生成)
7. 擴展知識:異步客戶端 Lettuce
7.1 Lettuce 簡介
- 基于 Netty 的異步非阻塞客戶端
- 支持響應(yīng)式編程(Reactor 模式)
- 適合高并發(fā)、高吞吐量場景
7.2 核心差異
特性 | Jedis | Lettuce |
---|---|---|
IO 模型 | 同步阻塞 | 異步非阻塞 |
連接方式 | 每個線程一個連接 | 單個連接處理多個請求 |
線程安全 | 非線程安全 | 線程安全 |
適用場景 | 簡單同步場景 | 異步 / 反應(yīng)式場景 |
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. 總結(jié):從入門到實戰(zhàn)的成長路徑
8.1 學(xué)習(xí)階段建議
- 基礎(chǔ)操作:掌握 Jedis 直接連接,理解 Redis 基本命令(SET/GET/HSET 等)
- 性能優(yōu)化:學(xué)習(xí)連接池原理,掌握 JedisPool 配置與使用
- 框架集成:深入 Spring Data Redis,學(xué)會配置 RedisTemplate 和序列化
- 實戰(zhàn)提升:在項目中應(yīng)用緩存、分布式鎖等場景,處理實際問題
8.2 核心知識圖譜
8.3 結(jié)語
通過本文的系統(tǒng)學(xué)習(xí),讀者應(yīng)能熟練掌握 Java 操作 Redis 的主流方式,理解不同連接方式的適用場景和底層原理,并能夠在實際項目中根據(jù)需求選擇合適的技術(shù)方案。記住,實踐是最好的老師,建議通過實際項目練習(xí)加深理解,遇到問題時結(jié)合官方文檔和源碼進行分析,逐步提升 Redis 開發(fā)與運維能力。
以上就是Java連接并操作Redis超詳細教程的詳細內(nèi)容,更多關(guān)于Java連接并操作Redis的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實現(xiàn)轉(zhuǎn)跳不同系統(tǒng)使用枚舉加switch的方式示例
今天小編就為大家分享一篇關(guān)于Java實現(xiàn)轉(zhuǎn)跳不同系統(tǒng)使用枚舉加switch的方式示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12SpringBoot中的JPA(Java?Persistence?API)詳解
這篇文章主要介紹了SpringBoot中的JPA(Java?Persistence?API)詳解,JPA用于將?Java?對象映射到關(guān)系型數(shù)據(jù)庫中,它提供了一種面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫,使得開發(fā)者可以更加方便地進行數(shù)據(jù)持久化操作,需要的朋友可以參考下2023-07-07使用mybatisPlus的queryWrapper做左聯(lián)接,內(nèi)聯(lián)接方式
本文介紹了如何使用Mybatis-Plus的QueryWrapper進行SQL查詢,包括左連接、內(nèi)連接等操作,通過示例代碼展示了如何構(gòu)建復(fù)雜的SQL查詢,并將結(jié)果存儲在List對象中返回,希望給讀者提供參考2025-03-03關(guān)于MyBatis中映射對象關(guān)系的舉例
這篇文章主要介紹了關(guān)于MyBatis中映射對象關(guān)系的舉例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06spring boot整合Shiro實現(xiàn)單點登錄的示例代碼
本篇文章主要介紹了spring boot整合Shiro實現(xiàn)單點登錄的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01