自己搭的一个分布式系统,使用的是springboot2.0.3+springcloud Finchley
当时在user服务中存入一个值,然后在api服务中使用相同的key取的时候发现取不出来,然后各种排除:
- 1 检查api服务和user服务中的redis连接的机器是否一致(一致)
2 分别写两个测试方法,断点跟进发现存入的时候没有问题,取得时候发现没有值,此时利用IntelliJ IDEA工具查询两个服务中的所有的key发现一个有,另外一个没有,推测应该是存入的key发生了变化。
通过可视化工具发现存入的key前面都有一串字符串,查了一下默认配置的时候是JdkSerializationRedisSerializer进行序列化数据,加上去的。它不仅仅会在value或hashvalue上加,也会在key和hashkey上加,所以取不到。
解决方式:设置RedisSerializer
方式一:
RedisConfig:
package com.fch.user.config.redisConfid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
@Configuration
public class RedisConfig {
private RedisTemplate redisTemplate;
@Autowired(required = false)
public void setRedisTemplate(RedisTemplate redisTemplate) {
RedisSerializer stringSerializer = new StringRedisSerializerUtil();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
this.redisTemplate = redisTemplate;
}
}
StringRedisSerializerUtil
package com.fch.user.config.redisConfid;
import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.Assert;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* 因为默认使用JdkSerializationRedisSerializer进行数据序列化 (包括key和value)
*/
public class StringRedisSerializerUtil implements RedisSerializer<Object> {
private final Charset charset;
private final String target = "\"";
private final String replacement = "";
/**
* {@link StringRedisSerializer} to use 7 bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode
* character set.
*
* @see StandardCharsets#US_ASCII
* @since 2.1
*/
public static final StringRedisSerializer US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII);
/**
* {@link StringRedisSerializer} to use ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
*
* @see StandardCharsets#ISO_8859_1
* @since 2.1
*/
public static final StringRedisSerializer ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1);
/**
* {@link StringRedisSerializer} to use 8 bit UCS Transformation Format.
*
* @see StandardCharsets#UTF_8
* @since 2.1
*/
public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);
/**
* Creates a new {@link StringRedisSerializer} using {@link StandardCharsets#UTF_8 UTF-8}.
*/
public StringRedisSerializerUtil() {
this(StandardCharsets.UTF_8);
}
/**
* Creates a new {@link StringRedisSerializer} using the given {@link Charset} to encode and decode strings.
*
* @param charset must not be {@literal null}.
*/
public StringRedisSerializerUtil(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
@Override
public byte[] serialize(Object o) throws SerializationException {
String string = JSON.toJSONString(o);
if (string == null) {
return null;
}
string = string.replace(target, replacement);
return string.getBytes(charset);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[])
*/
@Override
public String deserialize( byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
}
这种配置之后就可以正常了
方式二
因为发现方法名都比较怪,直接封装一下,实际上也是配置了序列化方式
RedisServiceImpl
package com.fch.user.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Created with IntelliJ IDEA.
* Date: 2018/7/25
* Time: 下午2:41
* Description: No Description
*/
@Slf4j
@Service
@SuppressWarnings({"unchecked","rawtypes"})
public class RedisServiceImpl {
/*@Autowired*/
private RedisTemplate redisTemplate;
/**
* 写入缓存
* @Title:set
* @Description:TODO
* @param :@param key
* @param :@param value
* @param :@return
* @return :boolean
* @throws
*/
public boolean set(final String key,Object value) {
boolean result = false;
try {
ValueOperations<Serializable,Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
log.error("==>>写入缓存出错" + e.getMessage());
}
return result;
}
/**
* 写入缓存设置过期时间
* @Title:set
* @Description:TODO
* @param :@param key
* @param :@param value
* @param :@param expireTime
* @param :@return
* @return :boolean
* @throws
*/
public boolean set(final String key, Object value, Long expireTime) {
log.info("--------------写入缓存设置过期时间---------------");
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
log.error("==>>写入缓存出错并设置过期时间" + e.getMessage());
}
return result;
}
/**
* 批量删除对应的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0)
redisTemplate.delete(keys);
}
/**
* 删除对应的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 哈希 添加
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 哈希获取数据
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表添加
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表获取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合添加
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合获取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合获取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key,double scoure,double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
@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;
}
}
2018-09-07