解決redisTemplate向redis中插入String類型數(shù)據(jù)時(shí)出現(xiàn)亂碼問題
前置知識(shí)
1.啥是redisTemplate?
redisTemplate是SpringDataRedis中的一個(gè)工具類,封裝了各種對(duì)Redis的操作,并將不同數(shù)據(jù)類型的操作API封裝到了不同的類型中
舉例:
下面的語句表示將【"name","谷歌"】這個(gè)k-v存入到redis中
redisTemplate.opsForValue().set("name","谷歌");
2.啥是序列化和反序列化?
序列化:將對(duì)象存入一個(gè)文件的過程。
反序列化:從一個(gè)文件中解析出對(duì)象。
問題描述
首先,這是一個(gè)Springboot+SpringDataRedis的項(xiàng)目
如果按照【前置知識(shí)】的例子中那樣寫,那么存入redis的將會(huì)是二進(jìn)制數(shù)據(jù),格式如下:
實(shí)際上這并不屬于啥錯(cuò)誤,將上面的二進(jìn)制轉(zhuǎn)化成String后,其實(shí)就是“谷歌”。
但這樣可讀性很差,且占用過多內(nèi)存。
成因分析
省流:由于沒有給自定義序列化方式,所以默認(rèn)采用的是jdk序列化器進(jìn)行序列化,導(dǎo)致最后存入的數(shù)據(jù)是二進(jìn)制。
以下是詳細(xì)分析過程:
這是如何調(diào)用redisTemplate并實(shí)現(xiàn)插入數(shù)據(jù)的一段代碼:
@SpringBootTest class SpringDataRedisDemoApplicationTests { @Resource private RedisTemplate redisTemplate; @Test void testString() { // 寫入String數(shù)據(jù) redisTemplate.opsForValue().set("name","谷歌"); } }
其中set方法的入?yún)?shù)據(jù)類型為兩個(gè)Object。
RedisTemplate可以接收任意Object作為值寫入Redis
當(dāng)沒有自定義序列化方式時(shí),默認(rèn)會(huì)使用jdk序列化器,redisTemplate的源碼中做了下面的定義:
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { @Override public void afterPropertiesSet() { ... if (defaultSerializer == null) { defaultSerializer = new JdkSerializationRedisSerializer( classLoader != null ? classLoader : this.getClass().getClassLoader()); } ... } }
jdk序列化器在底層會(huì)將Java對(duì)象轉(zhuǎn)成字節(jié)進(jìn)行存儲(chǔ),也就是之前看到的二進(jìn)制數(shù)據(jù)。
解決方案
1.改什么?
redisTemplate的源碼中其實(shí)規(guī)定了5種序列化器,其中四種默認(rèn)均為null。
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { private @Nullable RedisSerializer<?> defaultSerializer; private @Nullable RedisSerializer keySerializer = null; private @Nullable RedisSerializer valueSerializer = null; private @Nullable RedisSerializer hashKeySerializer = null; private @Nullable RedisSerializer hashValueSerializer = null; }
那么只要能改變序列化的方式,就能改變存入redis的數(shù)據(jù)類型。
RedisSerializer這個(gè)接口的實(shí)現(xiàn)類有下面幾種:
對(duì)于key一般使用 StringRedisSerializer ; (key一般是字符串)
而對(duì)于value一般使用 GenericJackson2JsonRedisSerializer 。(value可能是復(fù)雜的對(duì)象)
2.怎么改?
可以通過【配置類注入容器】來實(shí)現(xiàn)對(duì)序列化器的修改
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){ //創(chuàng)建RedisTemplate對(duì)象 RedisTemplate<String, Object> template = new RedisTemplate<>(); //設(shè)置連接工廠 template.setConnectionFactory(connectionFactory); //創(chuàng)建JSON序列化工具 GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); //設(shè)置key的序列化 template.setKeySerializer(RedisSerializer.string()); template.setHashKeySerializer(RedisSerializer.string()); //設(shè)置value的序列化 template.setValueSerializer(jsonRedisSerializer); template.setHashKeySerializer(jsonRedisSerializer); //返回 return template; } }
在注入redisTemplate對(duì)象時(shí),指定其泛型為<String,Object>
@SpringBootTest class SpringDataRedisDemoApplicationTests { @Autowired private RedisTemplate<String,Object> redisTemplate; @Test void testString() { // 寫入String數(shù)據(jù) redisTemplate.opsForValue().set("name","百度"); // 獲取String數(shù)據(jù) Object name = redisTemplate.opsForValue().get("name"); System.out.println(name); } }
3.報(bào)錯(cuò)怎么辦?
可能會(huì)報(bào)下面的錯(cuò)
Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/jsontype/impl/StdTypeResolverBuilder
at stu.demo.springdataredisdemo.config.RedisConfig.redisTemplate(RedisConfig.java:20)
引入下面的依賴即可
<!--Jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java利用future及時(shí)獲取多線程運(yùn)行結(jié)果
在Java編程中,有時(shí)候會(huì)需要及時(shí)獲取線程的運(yùn)行結(jié)果,本文就通過一個(gè)相關(guān)實(shí)例向大家介紹Java利用future及時(shí)獲取線程運(yùn)行結(jié)果的方法,需要的朋友可以參考。2017-10-10SpringBoot中dubbo+zookeeper實(shí)現(xiàn)分布式開發(fā)的應(yīng)用詳解
這篇文章主要介紹了SpringBoot中dubbo+zookeeper實(shí)現(xiàn)分布式開發(fā)的應(yīng)用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Eclipse中Properties和yml配置文件注釋亂碼的解決
這篇文章主要介紹了Eclipse中Properties和yml配置文件注釋亂碼的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Java利用Guava?Retry實(shí)現(xiàn)重處理
guava-retrying是谷歌的Guava庫的一個(gè)小擴(kuò)展,允許為任意函數(shù)調(diào)用創(chuàng)建可配置的重試策略,比如與正常運(yùn)行時(shí)間不穩(wěn)定的遠(yuǎn)程服務(wù)對(duì)話的函數(shù)調(diào)用。本文將利用其實(shí)現(xiàn)重處理,感興趣的可以了解一下2022-08-08idea?maven依賴引入失效無法正常導(dǎo)入依賴問題的解決方法
有時(shí)候idea導(dǎo)入一個(gè)新項(xiàng)目,或者pom文件修改(新增)了依賴,pom文件和代碼會(huì)報(bào)紅,提示依賴包不存在,下面這篇文章主要給大家介紹了關(guān)于idea?maven依賴引入失效無法正常導(dǎo)入依賴問題的解決方法,需要的朋友可以參考下2023-04-04