Redis 多数据源配置以及序列化器的使用
多数据源配置(非集群)
pom
<!--redis start-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--redis end-->
配置文件
redis:
open: true # 是否开启redis缓存 true开启 false关闭
database: 0
host:
port: 6379
password: # 密码(默认为空)
timeout: 60000 # 连接超时时长(毫秒)
jedis:
pool:
max-active: 200 # 连接池最大连接数(使用负值表示没有限制)
max-wait: 2000 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 20 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
max-total: 1024 #最大链接数
redis2:
host:
database: 0
port: 6379
password:
jedis:
pool:
max-active: 200 # 连接池最大连接数(使用负值表示没有限制)
max-wait: 2000 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 20 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
配置类
package com.ieslab.bigscreendatasvr.config;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.ieslab.common.util.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.*;
import org.springframework.util.ObjectUtils;
import redis.clients.jedis.JedisPoolConfig;
import java.time.Duration;
/**
* Redis配置
*
* @author
* @email sunlightcs@gmail.com
* @date 2017-07-70 19:22
*/
@Configuration
public class RedisConfig {
//数据源1
@Value("${spring.redis.host}")
private String processHost;
@Value("${spring.redis.port}")
private Integer processPort;
@Value("${spring.redis.password}")
private String processPassword;
@Value("${spring.redis.database}")
private Integer processDatabase;
//数据源2
@Value("${spring.redis2.host}")
private String psgesccHost;
@Value("${spring.redis2.port}")
private Integer psgesccPort;
@Value("${spring.redis2.password}")
private String psgesccPassword;
@Value("${spring.redis2.database}")
private Integer psgesccDatabase;
@Value("${spring.redis.timeout}")
private Long timeout;
@Value("${spring.redis.jedis.pool.max-active}")
private Integer maxActive;
@Value("${spring.redis.jedis.pool.max-wait}")
private Integer maxWait;
@Value("${spring.redis.jedis.pool.max-idle}")
private Integer maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private Integer minIdle;
@Value("${spring.redis.jedis.pool.max-total}")
private Integer maxTotal;
//配置工厂
public RedisConnectionFactory connectionFactory(String host, int port, String password, int maxIdle, int minIdle,
int maxTotal, long maxWaitMillis, int index) {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setPort(port);
if (!StringUtils.isEmpty(password)) {
jedisConnectionFactory.setPassword(password);
}
if (index != 0) {
jedisConnectionFactory.setDatabase(index);
}
jedisConnectionFactory.setPoolConfig(poolConfig(maxIdle, minIdle, maxTotal, maxWaitMillis, false));
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
//连接池配置
public JedisPoolConfig poolConfig(int maxIdle, int minIdle, int maxTotal, long maxWaitMillis, boolean testOnBorrow) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMinIdle(minIdle);
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxWaitMillis(maxWaitMillis);
poolConfig.setTestOnBorrow(testOnBorrow);
return poolConfig;
}
@Bean(name = "stringRedisProcessTemplate")
public StringRedisTemplate stringRedisProcessTemplate() {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(
connectionFactory(processHost, processPort, processPassword, maxIdle, minIdle, maxTotal, maxWait, processDatabase));
//FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
FastJsonConfig fastJsonConfig = new FastJsonConfig();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(stringRedisSerializer);
//template.afterPropertiesSet();
return template;
}
@Bean(name = "redisProcessTemplate")
public RedisTemplate<String, Object> redisProcessTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(
connectionFactory(processHost, processPort, processPassword, maxIdle, minIdle, maxTotal, maxWait, processDatabase));
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
FastJsonConfig fastJsonConfig = new FastJsonConfig();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
@Bean(name = "stringRedisPsgesccTemplate")
public StringRedisTemplate stringRedisPsgesccTemplate() {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(
connectionFactory(psgesccHost, psgesccPort, psgesccPassword, maxIdle, minIdle, maxTotal, maxWait, psgesccDatabase));
// FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
FastJsonConfig fastJsonConfig = new FastJsonConfig();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(stringRedisSerializer);
//template.afterPropertiesSet();
return template;
}
@Bean(name = "redisPsgesccTemplate")
public RedisTemplate<String, Object> redisPsgesccTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(
connectionFactory(psgesccHost, psgesccPort, psgesccPassword, maxIdle, minIdle, maxTotal, maxWait, psgesccDatabase));
// FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
FastJsonConfig fastJsonConfig = new FastJsonConfig();
StringRedisSerializer serializer = new StringRedisSerializer();
template.setKeySerializer(serializer);
template.setValueSerializer(serializer);
template.setHashKeySerializer(serializer);
template.setHashValueSerializer(serializer);
return template;
}
}
踩坑
数据源1的数据库存储的是json格式的 数据 数据源2 是String格式的 所以在序列化的时候出现了一些问题
首先说一下redis的序列化器
- GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
- Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的
- JacksonJsonRedisSerializer: 序列化object对象为json字符串
- JdkSerializationRedisSerializer: 序列化java对象
- StringRedisSerializer: 简单的字符串序列化
直接上异常 1
java.io.StreamCorruptedException: invalid stream header
相关代码(此时操作的是数据源2)
List<String> aclineloadfactor = (List<String>)redisUtil.
hGetAllByPipe("yourkeys:*");
/**
* 借助管道,实现Hash模糊匹配读取
*
* @param keyPattern key模糊匹配
* @return
*/
public Object hGetAllByPipe(String keyPattern){
Set<String> keys = stringRedisTemplate.keys(keyPattern);
List<Object> list = redisTemplate2.executePipelined(new RedisCallback<Object>() {
@Nullable
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (String key : keys) {
connection.hashCommands().hGetAll(key.getBytes());
}
return null;
}
});
ArrayList<String> strings = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
String jsonStr=gson.toJson(list.get(i));
strings.add(jsonStr);
}
return strings;
}
此时笔者用的是JdkSerializationRedisSerializer 产生这异常的原因是实体类需要实现Serializable接口 但是我要获取的是 List 不存在实体类的问题 于是换了 StringRedisSerializer 数据源2数据获取成功
异常2 直接上原始异常(操作数据源1)
[ERROR] 2021-08-05 18:09:30 [ TaskUtils$LoggingErrorHandler] : Unexpected error occurred in scheduled task
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.Object
at [Source: (byte[])"{
"plan":["062dc47fb3ba4aca94f39f81a160ac08","0ae67f78c5074f0384af5fcc219f103f","13724ab9f7264a8bb0e54f2061fb3ede","2f393db795964a9fb02ab53e7aaac8a7","368fdb4c47ea499590ba70358cad3a1d","441fd9296c734ee79365fef6c66f2912","45a7a8e573d34e4a85f6fc8fb1d4a549","467a0f8064a3455b860d1ba1ec099f75","53fd62c1754e42bf8bb4ccf1ff9f46f6","59ea6ae5bd214896800449216d57aa70","606f0d81275b4c19b5c9d378c26d802c","8acbd09819464669800c05c28dc9049e","d8fb34d7a82940adb3ac5fb54c25cdbe","e942003839a649628839937c9c5dcaba","[truncated 1053 bytes]; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.Object
at [Source: (byte[])"{
"plan":["062dc47fb3ba4aca94f39f81a160ac08","0ae67f78c5074f0384af5fcc219f103f","13724ab9f7264a8bb0e54f2061fb3ede","2f393db795964a9fb02ab53e7aaac8a7","368fdb4c47ea499590ba70358cad3a1d","441fd9296c734ee79365fef6c66f2912","45a7a8e573d34e4a85f6fc8fb1d4a549","467a0f8064a3455b860d1ba1ec099f75","53fd62c1754e42bf8bb4ccf1ff9f46f6","59ea6ae5bd214896800449216d57aa70","606f0d81275b4c19b5c9d378c26d802c","8acbd09819464669800c05c28dc9049e","d8fb34d7a82940adb3ac5fb54c25cdbe","e942003839a649628839937c9c5dcaba","[truncated 1053 bytes]; line: 1, column: 1]
at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:75)
at org.springframework.data.redis.core.AbstractOperations.deserializeValue(AbstractOperations.java:335)
at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:61)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:228)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:188)
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:96)
at org.springframework.data.redis.core.DefaultValueOperations.get(DefaultValueOperations.java:53)
at com.ieslab.utils.RedisUtils.get(RedisUtils.java:63)
at com.ieslab.utils.RedisUtils.get(RedisUtils.java:71)
at com.ieslab.bigscreendatasvr.datasvr.data.JxQlcDataCache.checkOverAllData(JxQlcDataCache.java:203)
at com.ieslab.bigscreendatasvr.datasvr.data.JxQlcDataCache.statisticsQlcData(JxQlcDataCache.java:120)
at com.ieslab.bigscreendatasvr.datasvr.service.impl.CyclStatisticsProcessImpl.calStatisData(CyclStatisticsProcessImpl.java:44)
at com.ieslab.bigscreendatasvr.config.TimerConfig.calStatsData(TimerConfig.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.Object
at [Source: (byte[])"{
"plan":["062dc47fb3ba4aca94f39f81a160ac08","0ae67f78c5074f0384af5fcc219f103f","13724ab9f7264a8bb0e54f2061fb3ede","2f393db795964a9fb02ab53e7aaac8a7","368fdb4c47ea499590ba70358cad3a1d","441fd9296c734ee79365fef6c66f2912","45a7a8e573d34e4a85f6fc8fb1d4a549","467a0f8064a3455b860d1ba1ec099f75","53fd62c1754e42bf8bb4ccf1ff9f46f6","59ea6ae5bd214896800449216d57aa70","606f0d81275b4c19b5c9d378c26d802c","8acbd09819464669800c05c28dc9049e","d8fb34d7a82940adb3ac5fb54c25cdbe","e942003839a649628839937c9c5dcaba","[truncated 1053 bytes]; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1627)
at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1377)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:141)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:96)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71)
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:712)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3318)
at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:73)
... 27 more
此时笔者用的是Jackson2JsonRedisSerializer 换成 FastJsonRedisSerializer 就解决了 但是具体原因未知 望熟悉这个的大佬指点一下