Redis - RedisTemplate及4種序列化方式深入解讀
文章目錄
概述
RedisTemplate
StringRedisTemplate
RedisSerializer 序列化 介面
JDK 序列化方式 (預設)
String 序列化方式
JSON 序列化方式
示例
XML 序列化方式
概述
使用Spring 提供的 Spring Data Redis 操作redis 必然要使用Spring提供的模板類 RedisTemplate, 今天我們好好的看看這個模板類 。
RedisTemplate
看看4個序列化相關的屬性 ,主要是 用於 KEY 和 VALUE 的序列化 。 舉個例子,比如說我們經常會將POJO 物件儲存到 Redis 中,一般情況下會使用 JSON 方式序列化成字串,儲存到 Redis 中 。
Spring提供的Redis資料結構的操作類
ValueOperations 類,提供 Redis String API 操作
ListOperations 類,提供 Redis List API 操作
SetOperations 類,提供 Redis Set API 操作
ZSetOperations 類,提供 Redis ZSet(Sorted Set) API 操作
GeoOperations 類,提供 Redis Geo API 操作
HyperLogLogOperations 類,提供 Redis HyperLogLog API 操作
StringRedisTemplate
再看個常用的 StringRedisTemplate
RedisTemplate<K, V> 支援泛型,StringRedisTemplate K V 均為String型別。
org.springframework.data.redis.core.StringRedisTemplate 繼承 RedisTemplate 類,使用 org.springframework.data.redis.serializer.StringRedisSerializer 字串序列化方式。
RedisSerializer 序列化 介面
RedisSerializer介面 是 Redis 序列化介面,用於 Redis KEY 和 VALUE 的序列化
RedisSerializer 介面的實現類 如下
歸類一下
JDK 序列化方式 (預設)
String 序列化方式
JSON 序列化方式
XML 序列化方式
JDK 序列化方式 (預設)
org.springframework.data.redis.serializer.JdkSerializationRedisSerializer ,預設情況下,RedisTemplate 使用該資料列化方式。
我們來看下原始碼 RedisTemplate#afterPropertiesSet()
Spring Boot 自動化配置 RedisTemplate Bean 物件時,就未設定預設的序列化方式。
絕大多數情況下,不推薦使用 JdkSerializationRedisSerializer 進行序列化。主要是不方便人工排查資料。
我們來做個測試
執行單元測試
看不懂呀 ,老哥
KEY 前面帶著奇怪的 16 進位制字元 , VALUE 也是一串奇怪的 16 進位制字元 。。。。。
為什麼是這樣一串奇怪的 16 進位制? ObjectOutputStream#writeString(String str, boolean unshared) 實際就是標誌位 + 字串長度 + 字串內容
KEY 被序列化成這樣,線上通過 KEY 去查詢對應的 VALUE非常不方便,所以 KEY 肯定是不能被這樣序列化的。
VALUE 被序列化成這樣,除了閱讀可能困難一點,不支援跨語言外,實際上也沒還OK。不過,實際線上場景,還是使用 JSON 序列化居多。
String 序列化方式
org.springframework.data.redis.serializer.StringRedisSerializer ,字串和二進位制陣列的直接轉換
絕大多數情況下,我們 KEY 和 VALUE 都會使用這種序列化方案。
JSON 序列化方式
org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer 使用 Jackson 實現 JSON 的序列化方式,並且從 Generic 單詞可以看出,是支援所有類。
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {
.....
.....
if (StringUtils.hasText(classPropertyTypeName)) {
mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, classPropertyTypeName);
} else {
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
}
}
classPropertyTypeName 不為空的話,使用傳入物件的 classPropertyTypeName 屬性對應的值,作為預設型別(Default Typing) ,否則使用傳入物件的類全名,作為預設型別(Default Typing)。
我們來思考下,在將一個物件序列化成一個字串,怎麼保證字串反序列化成物件的型別呢?Jackson 通過 Default Typing ,會在字串多冗餘一個型別,這樣反序列化就知道具體的型別了
先說個結論
標準JSON
{
"id": 100,
"name": "小工匠",
"sex": "Male"
}
使用 Jackson Default Typing 機制序列化
{
"@class": "com.artisan.domain.Artisan",
"id": 100,
"name": "小工匠",
"sex": "Male"
}
示例
測試一把
【配置類】
@Bean
public RedisTemplate<String, Object> redisTemplate() {
// 建立 RedisTemplate 物件
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 設定 RedisConnection 工廠。 它就是實現多種 Java Redis 客戶端接入的祕密工廠
template.setConnectionFactory(connectionFactory);
// 使用 String 序列化方式,序列化 KEY 。
template.setKeySerializer(RedisSerializer.string());
// 使用 JSON 序列化方式(庫是 Jackson ),序列化 VALUE 。
template.setValueSerializer(RedisSerializer.json());
return template;
}
【單元測試】
@Test
public void testJacksonSerializer() {
Artisan artisan = new Artisan();
artisan.setName("小工匠");
artisan.setId(100);
artisan.setSex("Male");
// set
redisTemplate.opsForValue().set("artisan", artisan);
}
【結果】
是不是多了@class 屬性,反序列化的物件的型別就可以從這裡獲取到。
@class 屬性看似完美解決了反序列化後的物件型別,但是帶來 JSON 字串佔用變大,所以實際專案中,我們很少採用 Jackson2JsonRedisSerializer
XML 序列化方式
org.springframework.data.redis.serializer.OxmSerializer使用 Spring OXM 實現將物件和 String 的轉換,從而 String 和二進位制陣列的轉換。 沒見過哪個專案用過,不囉嗦了