关于spring boot2以上的redis多库使用踩坑

Posted 摩尔迦娜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于spring boot2以上的redis多库使用踩坑相关的知识,希望对你有一定的参考价值。

最近项目跟其他公司合作,登录用户使用他们的接口,用户信息放在一个9号db的redis里使用,本身项目也用了redis,使用的是0号db。

最开始想的是在代码里面手动切换,用一个redisTemplate,找来找去发现网上说2.0以上是这么切换redis的

Optional.ofNullable((LettuceConnectionFactory) redisTemplate.getConnectionFactory())
  .ifPresent(
    factory -> {
      factory.setDatabase(9);      
      redisTemplate.setConnectionFactory(factory);
      factory.resetConnection();
    }

);

放到代码里发现,怎么切换插入的都是0 db里面,坑爹啊,有的说换redis依赖版本就行了,但有篇文章说了是resetConection()并没有真正的按新的设置初始化redis,按照上边加了一条语句

Optional.ofNullable((LettuceConnectionFactory) redisTemplate.getConnectionFactory())
  .ifPresent(
    factory -> {
      factory.setDatabase(9);
      redisTemplate.setConnectionFactory(factory);
      factory.resetConnection();
      factory.afterPropertiesSet();//按新的设置初始化
    }
);

然后代码里测试了下,果然切换成功了,但真的没问题了么?

这时候又在其他类里使用redisTemplate,发现怎么操作的也是9 db?

这怎么行,不可能每次切换后,还得切换回来吧,而且要是同时的并发操作,也会在切换过程中造成其他的提交失败,这个方案只能废弃。

这时想到,一个实例不行,那就实例化二个不就行了,每个对应分别各自的db,这样也不会操作冲突。

@Configuration
@ConfigurationProperties(prefix = "spring.redis.other", ignoreInvalidFields = true)
@Data
@RefreshScope
public class RedisTemplateConfig {

    @Resource
    private final RedisConnectionFactory redisConnectionFactory;

    private String host = "127.0.0.1";
    private String password = null;
    private Integer port =6367;
    private Integer database = 9;

    @Bean
    public RedisTemplate<String, Object> redisOtherTemplate() {
        /* ========= 基本配置 ========= */
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName(host);
        configuration.setPort(port);
        configuration.setDatabase(database);
        if (!ObjectUtils.isEmpty(password)) {
            RedisPassword redisPassword = RedisPassword.of(password);
            configuration.setPassword(redisPassword);
        }
        /* ========= 连接池通用配置 ========= */
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxTotal(20);
        genericObjectPoolConfig.setMinIdle(0);
        genericObjectPoolConfig.setMaxIdle(10);
        genericObjectPoolConfig.setMaxWaitMillis(-1);
        /* ========= lettuce pool ========= */
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
        builder.poolConfig(genericObjectPoolConfig);
        builder.commandTimeout(Duration.ofSeconds(2000));
        LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, builder.build());
        connectionFactory.afterPropertiesSet();
        /* ========= 创建 template ========= */
        return createRedisTemplate(connectionFactory);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    public RedisTemplate<String, Object> createRedisTemplate(RedisConnectionFactory newFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(newFactory);
        return redisTemplate;
    }
}

分别注入使用就可以了

@Component
@AllArgsConstructor
public class InitCacheRunner implements ApplicationRunner {
    private final RedisTemplate redisTemplate;
    private final RedisTemplate redisOtherTemplate;
}

最后读取其他公司的redis内容时,又出现个问题 cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException

这个是因为对面存的时候,设置的序列化跟我取的时候序列化方式不一样,会出现这个错误,

在初始化redis的时候设置下对方序列化的方式就行了

redisTemplate.setValueSerializer(new GenericToStringSerializer<String>(String.class));

大功告成,如果以后出问题再回来记下吧

 

以上是关于关于spring boot2以上的redis多库使用踩坑的主要内容,如果未能解决你的问题,请参考以下文章

spring boot2 集成Redis

Spring Boot2.0之整合Redis

Spring Boot2.X 自定义Redis的cacheManager,保存Json格式到Redis

SpringBoot之整合Redis分析和实现-基于Spring Boot2.0.2版本

spring boot2 运行环境

关于Spring boot2.0+配置拦截器拦截静态资源的问题