SpringDataRedis
SpringData是Spring中數據操作的模塊,包含對各種數據庫的集成,其中對Redis集成模塊就叫做SpringDataRedis,
官方地址:https://spring.io/projects/spring-data-redis
特性:
- 提供了對不同Redis客戶端的整合(Lettuce和Jedis)
- 提供了RedisTemplate統一API來操作Redis
- 支持Redis的發布訂閱模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的響應式變成
- 支持基于JDK、JSON、字符串、Spring對象的數據序列化及反序列化
- 支持基于Redis的JDK Collection實現
文章目錄
- SpringDataRedis
- 一、SpringDataRedis快速入門
- 1.引入依賴
- 2.配置文件
- 3.注入RedisTemplate
- 4.編寫測試
- 二、SpringDataRedis的序列化方式
- RedisTemplate序列化器源碼分析
- 方式一:自定義RedisTemplate的序列化方式
- 編寫RedisTemplate序列化器的配置
- 方式二: StringRedisTemplate
- 1. 依賴注入
- 2. 編寫測試
一、SpringDataRedis快速入門
API | 返回值類型 | 說明 |
---|---|---|
redisTemplate.opsForValue() | ValueOperations | 操作String類型數據 |
redisTemplate.opsForHash | HashOperations | 操作Hash類型數據 |
redisTemplate.opsForList | ListOperations | 操作List類型數據 |
redisTemplate.opsForSet | SetOperations | 操作Set類型數據 |
redisTemplate.opsForZSet | ZSetOperations | 操作SortedSet類型數據 |
redisTemplate | 通用的命令 |
1.引入依賴
<!-- Redis依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 連接池依賴 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- Jackson依賴(如果使用了SpringMVC則無需引入) --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>
2.配置文件
spring:redis:host: 127.0.0.1port: 6379password:database: 2lettuce:pool: # 默認使用lettuce連接池,如需切換為jedis,請注釋掉此部分,并加入對jedis的依賴max-active: 8 # 最大連接數max-idle: 8 # 最大空閑連接數min-idle: 0 # 最小空閑連接數max-wait: 1000 # 最大等待時間
3.注入RedisTemplate
@Autowiredprivate RedisTemplate<String, String> redisTemplate;
4.編寫測試
@Testvoid testString() {// 寫入一條String數據redisTemplate.opsForValue().set("name", "查理布朗");// 獲取String數據String name = redisTemplate.opsForValue().get("name");System.out.println("name = " + name);}
二、SpringDataRedis的序列化方式
當自動注入寫作@Autowired private RedisTemplate redisTemplate;
時,
未指定RedisTemplate<K, V>
的key和value類型,默認key和value都為Object,寫入redis時redisTemplate
會根據RedisSerializer
自動完成對象的序列化操作(默認使用JdkSerializationRedisSerializer
完成對對象的序列化操作),
因此會存在:當key和value為String時,存入的key和value顯示亂碼(修改為String序列化器后即可恢復正常)
可讀性差、內存占用較大
RedisTemplate序列化器源碼分析
RedisTemplate可以接收任意Object作為值寫入Redis,寫入前會把Object通過不同的RedisSerializer
序列化為字節形式。
如果 key
、valuie
、hashKey
、hashValue
的序列化器沒有初始值,則會使用默認序列化器defaultSerializer
在RedisTemplate.java
源碼中,我們可以看到默認的序列化器defaultSerializer
是JdkSerializationRedisSerializer
通過對redisTemplate.opsForValue().set("name", "查理布朗")
的set
方法debug,底層使用ObjectOutPutStream
將Java對象寫為字節后存入Redis
方式一:自定義RedisTemplate的序列化方式
- 自定義RedisTemplate
- 修改RedisTemplate的序列化器為GenericJackson2JsonRedisSerializer
編寫RedisTemplate序列化器的配置
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {// 創建RedisTemplate對象RedisTemplate<String, Object> template = new RedisTemplate<>();// 設置連接工廠template.setConnectionFactory(connectionFactory);// 創建JSON序列化器GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// 設置Key的序列化器template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());// 設置Value的序列化器template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);// 返回return template;}}
盡管Json的序列化方式可以滿足我們的需求,但依然存在一些問題,如圖:
為了在反序列化時直到對象的類型,JSON序列化器會將類的class類型寫入json結果中,存入Redis,會帶來額外的內存開銷。
為了節省內存空間,我們并不會使用JSON序列化器來處理value,而是統一使用String序列化器,要求只能存儲String類型的key和value。當需要存儲Java對象時,手動完成對象的序列化和反序列化。
方式二: StringRedisTemplate
- 使用StringRedisTemplate
- 寫入Redis時,手動把對血啊ing序列化為JSON
- 讀取Redis時,手動把讀取到的JSON反序列化為對象
在Spring中,默認提供了一個StringRedisTemplate類,它的key和value的序列化方式默認都是String方式。省去了我們自定義RedisTemplate的過程:
1. 依賴注入
@Autowiredprivate StringRedisTemplate stringRedisTemplate;
2. 編寫測試
import com.fasterxml.jackson.databind.ObjectMapper;// JSON工具private static final ObjectMapper mapper = new ObjectMapper();@Testvoid testStringTemplate() throws JsonProcessingException {// 準備對象User user = new User("查理二世", 30);// 手動序列化String json = mapper.writeValueAsString(user);// 寫入到redisstringRedisTemplate.opsForValue().set("user:200", json);// 讀取數據String val = stringRedisTemplate.opsForValue().get("user:200");// 反序列化User user1 = mapper.readValue(val, User.class);System.out.println("user1 = " + user1);}@Testvoid testHash() {// 寫入數據stringRedisTemplate.opsForHash().put("user:400", "name", "查理三世");stringRedisTemplate.opsForHash().put("user:400", "age", "40");// 獲取數據Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:400");System.out.println("entries = " + entries); // entries = {name=查理三世, age=40}}
該方式消除了@class
,節約了存儲空間。