最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決RedisTemplate的key默認(rèn)序列化器的問(wèn)題

 更新時(shí)間:2021年03月02日 14:24:59   作者:閉門車  
這篇文章主要介紹了解決RedisTemplate的key默認(rèn)序列化器的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

redis的客戶端換成了spring-boot-starter-data-redis,碰到了一個(gè)奇怪的問(wèn)題,

在同一個(gè)方法中

1.先hset,再hget,正常獲得數(shù)據(jù)。

在不同的方法中 先hset,再hget獲取不到數(shù)據(jù),通過(guò)redis的monitor監(jiān)控發(fā)現(xiàn)了命令的問(wèn)題:

實(shí)際我的key為JK_HASH:csrk,hashkey為user,但是根據(jù)上圖所示,實(shí)際執(zhí)行的命令多了好多其他字符,這是什么原因呢?

在服務(wù)器端先確認(rèn)發(fā)現(xiàn)實(shí)際有這個(gè)Hash,通過(guò)hset可以得到正確的數(shù)據(jù),所以第一次執(zhí)行hset的時(shí)候命令是正常的,問(wèn)題可能出現(xiàn)在hget上面,先打開(kāi)源碼看一下

 @SuppressWarnings("unchecked")
 public HV get(K key, Object hashKey) {
 final byte[] rawKey = rawKey(key);
 final byte[] rawHashKey = rawHashKey(hashKey);
 
 byte[] rawHashValue = execute(new RedisCallback<byte[]>() {
 
 public byte[] doInRedis(RedisConnection connection) {
 return connection.hGet(rawKey, rawHashKey);
 }
 }, true);
 
 return (HV) deserializeHashValue(rawHashValue);
 }

從這里可以看到實(shí)際上傳給redis的都是byte數(shù)據(jù),而byte數(shù)組是rawKey和rawHashKey生成的,先看下rawKey方法

 @SuppressWarnings("unchecked")
 byte[] rawKey(Object key) {
 Assert.notNull(key, "non null key required");
 if (keySerializer() == null && key instanceof byte[]) {
 return (byte[]) key;
 }
 return keySerializer().serialize(key);
 }

然后進(jìn)一步跟蹤keySerializer()方法

 RedisSerializer keySerializer() {
 return template.getKeySerializer();
 }
 public RedisSerializer<?> getKeySerializer() {
 return keySerializer;
 }

最后跟蹤到是RedisTemplate中的屬性keySerializer導(dǎo)致的,而通過(guò)打印keySerializer的class發(fā)現(xiàn) 默認(rèn)使用的是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,但它是如何進(jìn)行初始化的呢,默認(rèn)的構(gòu)造函數(shù)中并沒(méi)有對(duì)該屬性進(jìn)行初始化。

根據(jù)RedisTemplate的類關(guān)系發(fā)現(xiàn)它是繼承RedisAccessor的,而此類是實(shí)現(xiàn)的org.springframework.beans.factory.InitializingBean接口,這個(gè)接口有個(gè)特性,凡是繼承該接口的類,在初始化bean的時(shí)候會(huì)執(zhí)行afterPropertiesSet方法。

而afterPropertiesSet方法中,確實(shí)對(duì)keySerializer進(jìn)行了初始化:

 public void afterPropertiesSet() {
 super.afterPropertiesSet();
 boolean defaultUsed = false;
 if (defaultSerializer == null) {
 defaultSerializer = new JdkSerializationRedisSerializer(
 classLoader != null ? classLoader : this.getClass().getClassLoader());
 }
 if (enableDefaultSerializer) {
 if (keySerializer == null) {
 keySerializer = defaultSerializer;
 defaultUsed = true;
 }
 if (valueSerializer == null) {
 valueSerializer = defaultSerializer;
 defaultUsed = true;
 }
 if (hashKeySerializer == null) {
 hashKeySerializer = defaultSerializer;
 defaultUsed = true;
 }
 if (hashValueSerializer == null) {
 hashValueSerializer = defaultSerializer;
 defaultUsed = true;
 }
 }
 if (enableDefaultSerializer && defaultUsed) {
 Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
 }
 if (scriptExecutor == null) {
 this.scriptExecutor = new DefaultScriptExecutor<K>(this);
 }
 initialized = true;
 }

在這里可以看到默認(rèn)使用的正是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,而問(wèn)題正在這里,通過(guò)查詢可以發(fā)現(xiàn)序列化器有這些,而在這里我們需要使用的是StringRedisSerializer

加入如下代碼:

 @Autowired(required = false)
 public void setRedisTemplate(RedisTemplate redisTemplate) {
  RedisSerializer stringSerializer = new StringRedisSerializer();
  redisTemplate.setKeySerializer(stringSerializer);
  redisTemplate.setValueSerializer(stringSerializer);
  redisTemplate.setHashKeySerializer(stringSerializer);
  redisTemplate.setHashValueSerializer(stringSerializer);
  this.redisTemplate = redisTemplate;
 }

重新進(jìn)行測(cè)試,方法1hset,方法2hget,方法2能拿到正確的數(shù)據(jù),完畢。

補(bǔ)充:redisTemplate取對(duì)象時(shí)反序列化失敗

錯(cuò)誤:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field

注意:反序列化時(shí)要保證實(shí)體對(duì)象有一個(gè)無(wú)參構(gòu)造函數(shù),否則反序列化也會(huì)失敗

json序列化是根據(jù)set和get方法來(lái)序列化字段的,如果方法正好有set和get開(kāi)頭但沒(méi)有對(duì)應(yīng)field,那么反序列化就會(huì)失敗。

可以在實(shí)體類加上注解@JsonIgnoreProperties(ignoreUnknown = true)忽略實(shí)體中沒(méi)有對(duì)應(yīng)的json的key值,或者在set方法上加上@JsonIgnore注解,如果是用mongoDb數(shù)據(jù)庫(kù),第二種方法那么就不大適用了,總不能去ObjectId類操作,這是修改別人的源代碼。

以下是redisTemplate在springboot2.x里面存取對(duì)象的配置,等同于第一種方法

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
 @Bean
 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
  RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  redisTemplate.setConnectionFactory(connectionFactory);
  //Use Jackson 2Json RedisSerializer to serialize and deserialize the value of redis (default JDK serialization)
  Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//將類名稱序列化到j(luò)son串中,去掉會(huì)導(dǎo)致得出來(lái)的的是LinkedHashMap對(duì)象,直接轉(zhuǎn)換實(shí)體對(duì)象會(huì)失敗
  objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  //設(shè)置輸入時(shí)忽略JSON字符串中存在而Java對(duì)象實(shí)際沒(méi)有的屬性
  objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
 
  //Use String RedisSerializer to serialize and deserialize the key value of redis
  RedisSerializer redisSerializer = new StringRedisSerializer();
  //key
  redisTemplate.setKeySerializer(redisSerializer);
  redisTemplate.setHashKeySerializer(redisSerializer);
  //value
  redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
  redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 
  redisTemplate.afterPropertiesSet();
  return redisTemplate; 
 } 
}

application.properties文件添加如下,springboot2.x連接池用的是lettuce

spring.redis.host=localhost
spring.redis.password=
# 連接超時(shí)時(shí)間(毫秒)
spring.redis.timeout=3000ms
# Redis默認(rèn)情況下有16個(gè)分片,這里配置具體使用的分片,默認(rèn)是0
spring.redis.database=0
# 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制) 默認(rèn) 8
spring.redis.lettuce.pool.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制) 默認(rèn) -1
spring.redis.lettuce.pool.max-wait=-1
# 連接池中的最大空閑連接 默認(rèn) 8
spring.redis.lettuce.pool.max-idle=8
# 連接池中的最小空閑連接 默認(rèn) 0
spring.redis.lettuce.pool.min-idle=0

添加數(shù)據(jù)進(jìn)redis

 @Test
 public void testRedis() {
  Headset headset = new Headset();
  redisTemplate.opsForValue().set("test:123", headset);
  System.out.println(redisTemplate.opsForValue().get("test:123"));
 }

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

最新評(píng)論

诏安县| 花垣县| 饶河县| 江山市| 安多县| 义马市| 沧州市| 且末县| 游戏| 鹤峰县| 昆明市| 许昌市| 无棣县| 赤峰市| 霞浦县| 新郑市| 本溪| 苏尼特左旗| 泽州县| 开江县| 锦屏县| 乐陵市| 鹤庆县| 平定县| 天全县| 临海市| 康马县| 九台市| 杭州市| 宁阳县| 三门县| 安陆市| 三江| 疏附县| 青河县| 香格里拉县| 台中市| 西畴县| 盐边县| 辽阳市| 得荣县|