SpringDataRedis
簡介
SpringData
是Spring
中專門進行數據操作的模塊,包含了對于各種數據庫的集成。其中對Redis
的集成模塊叫做SpringDataRedis
(官網地址:Spring Data Redis)。其最核心的特點就是提供了不同Redis
客戶端的整合:結合了Jedis
和Lettuce
;提供了RedisTemplate
這個統一的操作模板來操作Redis
,下圖是SpringDataRedis
的其他特點:
由于Spring
系列的強大生態支持,和SpringDataRedis
本身優秀的使用體驗,現在越來越多的企業傾向于使用SpringDataRedis
作為Redis
的Java
客戶端,同時本人也推薦大家使用SpringDataRedis
。
SpringDataRedis
快速入門
引入依賴
我們使用SpringBoot
框架來進行SpringBootRedis
的快速入門。由于SpringBoot
已經提供了對SpringDataRedis
的支持(可以在創建SpringBoot
項目的時候將SpringDataRedis
的依賴引入到pom.xml
文件中),所以說使用起來非常的簡單,如果沒有在創建項目時引入依賴,也可以進行手動引入,在引入時不但需要SpringDataRedis
的依賴,還需要一個連接池依賴來實現連接池(commons-pool2
):
<!-- SpringDataRedis依賴 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>3.4.6</version>
</dependency>
<!-- 連接池依賴 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.12.0</version>
</dependency>
配置文件
因為我們使用了SpringBoot
框架,所以說對于Redis
連接的配置我們可以直接基于application
文件進行配置:
spring:data:redis:host: 192.168.181.134port: 6379password: your password# 連接池配置lettuce:pool:max-active: 8 # 最大連接數max-idle: 8 # 最大空閑連接min-idle: 4 # 最小空閑連接max-wait: 1000ms # 連接等待時間
在配置連接池的時候需要特別注意,可以使用Jedis
和Lettuce
兩個連接池:
而Spring
默認使用的是Lettuce
連接池,可以從Maven
依賴傳遞中看出:
而我們并沒有引入Jedis
的依賴,所以說在配置連接池的時候使用Lettuce
即可,如果想要使用Jedis
連接池,則需要引入對應的依賴。
編碼操作
上文提到了SpringDataRedis
提供了一個RedisTemplate
這個統一的操作模板來操作Redis
,所以說想要使用SpringDataRedis
只需要學會RedisTemplate
即可。RedisTemplate
中封裝了各種對于Redis
的操作,并且將不同數據類型的操作API
封裝到了不同的類型中:
下面是一個簡單的RedisTemplate
操作示例:
package com.wzb;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;@SpringBootTest
class RedisSpringDataApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid testString() {// 存儲一條String數據redisTemplate.opsForValue().set("name", "jack");// 獲取String數據Object name = redisTemplate.opsForValue().get("name");System.out.println(name);}}
這是一個SpringBoot
的測試類,其中通過@Autowired注解
注入了RedisTemplate
,然后在測試方法中,通過opsForValue
來操作String類型
的數據,并且通過set方法
存入一條Key
為name
,Value
為jack
的數據。但是這樣存入數據之后,我們是無法正常讀取的,讓我們通過可視化界面查看一下剛才存入的數據:
我們可以看到在我們原本的Key:name
之間有一大串字符,在原本的Value:jack
之前也有一大串字符。這是因為RedisTemplate
在存入數據之前需要將數據序列化,而默認的序列化器是JdkSerializationRedisSerializer
也就是JDK
的默認序列化器,該序列化器會將Java
對象轉換為Java
標準的二進制序列化,而那些十六進制的特殊字符是JDK
序列化的魔法數
。這樣的狀況顯然不是我們想看到的,因為這樣的話存入的Key-Value
的值完全被改變了,無法直接進行讀取或修改,此時,就需要配置RedisTemplate
的序列化器。
配置RedisTemplate
的序列化器
通過觀察RedisTemplate
的源代碼發現,RedisTemplate
一共可以支持4個序列化器的配置,并且由于這4個序列化器的配置都是null
,所以說會使用默認的JdkSerializationRedisSerializer
序列化器。可供選擇的Serializer
如圖所示:
一般對于Key
的序列化會使用StringRedisSerializer
,而Value
的序列化器使用 genericJackson2JsonRedisSerializer
,這個序列化器會將Java對象
轉為Json字符串
然后再存儲到Redis
中。
我們可以創建一個類來完成RedisTemplate
的序列化器配置:
package com.wzb.config;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.RedisSerializer;/*** Redis序列化設置*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {// 創建RedisTemplate對象RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();// 設置連接工廠redisTemplate.setConnectionFactory(redisConnectionFactory);// 創建Json序列化工具GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// 設置Key序列化redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setHashKeySerializer(RedisSerializer.string());// 設置Value序列化redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);// 返回return redisTemplate;}}
想要使用genericJackson2JsonRedisSerializer
序列化器還需要引入Json
相關依賴:
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>
然后就可以修改原來代碼,注入我們自定義序列化器的RedisTemplate
:
@Autowired
private RedisTemplate<String, Object> redisTemplate;
測試之后發現,存入的數據是我們想要的結果:
然后測試存入一個Java
對象:
@Test
void testObject() {redisTemplate.opsForValue().set("user", new User("zhangsan", 20));User user = (User)redisTemplate.opsForValue().get("user");System.out.println(user);
}
發現存取都是沒有問題的,更換RedisTemplate
序列化器成功。
StringRedisTemplate
在使用genericJackson2JsonRedisSerializer
序列化器存儲一個Java
對象時,除了對象的屬性外,還會存儲這個類的全類名
以便于反序列化。這樣看似很方便,但實際上存在一個很大的問題:耗費了太多的額外存儲空間。因為Redis
是基于內存的,眾所周知,內存是十分寶貴的,所以說要盡量高效地使用內存,將全類名存入Redis
是不推薦的做法。
解決方法就是對于Value
,也使用和Key
一樣的StringRedisSerializer
序列化器,將Value
當作String
類型進行處理,然后在Java
代碼中通過程序手動序列化和反序列化。Spring
早就為我們考慮到了這一點,于是提供了一個StringRedisTemplate
工具,其Key
和Value
的序列化器就是StringRedisSerializer
:
我們就可以使用StringRedisTemplate
來操作,而無需自己去設置序列化器:
package com.wzb;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzb.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;import java.util.Map;@SpringBootTest
public class StringRedisTemplateTests {@Autowiredprivate StringRedisTemplate stringRedisTemplate;private static final ObjectMapper mapper = new ObjectMapper();@Testvoid testSave() throws JsonProcessingException {// 創建對象User user = new User("lisi", 25);// 手動序列化String json = mapper.writeValueAsString(user);// 寫入數據stringRedisTemplate.opsForValue().set("user", json);// 獲取數據String jsonUser = stringRedisTemplate.opsForValue().get("user");// 手動反序列化User readUser = mapper.readValue(jsonUser, User.class);System.out.println(readUser);}}
使用了StringRedisTemplate
之后,需要我們手動進行對象的序列化和反序列化,其他的操作和使用RedisTemplate
并無差別,但是這樣之后,存儲一個Java
對象就不會再存儲其字節碼等額外信息了:
這樣做會增加額外的代碼處理,但是可以極大的節約內存資源,是推薦的做法。