首页 > 数据库 >SpringBoot声明连接多个redis数据源配置模版

SpringBoot声明连接多个redis数据源配置模版

时间:2023-05-23 11:05:32浏览次数:45  
标签:SpringBoot 数据源 redis redisKey springframework org import public


在实际开发中,我们可能会用到2个不同的redis数据源;如何连接查询详情:


文章目录

  • 一、依赖
  • 二、配置文件
  • 三、config类配置
  • 四、序列化问题
  • 五、封装工具类


一、依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

二、配置文件

spring:
  redis:
    lettuce:
      pool:
        connTimeout: 10000
        maxIdle: 100
        minIdle: 1
        maxActive: 200
        maxWait: 2
  redis-data:
    host: ip1
    port: 6679
    password: 123456
    db: 0
  redis-concurrency:
    host: ip2
    port: 6779
    password: 1111

三、config类配置

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * 配置lettuce连接池
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
    public GenericObjectPoolConfig redisPool() {
        return new GenericObjectPoolConfig<>();
    }

    /**
     * 配置第一个数据源的连接工厂
     * 这里注意:需要添加@Primary 指定bean的名称,目的是为了创建两个不同名称的LettuceConnectionFactory
     *
     * @return
     */
    @Bean("dataFactory")
    @Primary
    public LettuceConnectionFactory dataFactory(@Value("${spring.redis-data.host}") String host,
                                                @Value("${spring.redis-data.port}") int port,
                                                @Value("${spring.redis-data.password}") String password,
                                                @Value("${spring.redis-data.db}") int db,
                                                GenericObjectPoolConfig config) {
        RedisStandaloneConfiguration redisDataConfig = new RedisStandaloneConfiguration(host, port);
        redisDataConfig.setDatabase(db);
        redisDataConfig.setPassword(RedisPassword.of(password));
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        LettuceConnectionFactory factory = new LettuceConnectionFactory(redisDataConfig, clientConfiguration);
        return factory;
    }

    //第二个数据源的连接工厂
    @Bean("concurrencyFactory")
    public LettuceConnectionFactory concurrencyFactory(@Value("${spring.redis-concurrency.host}") String host,
                                                       @Value("${spring.redis-concurrency.port}") int port,
                                                       @Value("${spring.redis-concurrency.password}") String password,
                                                                  GenericObjectPoolConfig config) {
        RedisStandaloneConfiguration redisDataConfig = new RedisStandaloneConfiguration(host, port);
        redisDataConfig.setPassword(RedisPassword.of(password));
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        LettuceConnectionFactory factory = new LettuceConnectionFactory(redisDataConfig, clientConfiguration);
        return factory;
    }


    /**
     * 配置第一个数据源的RedisTemplate
     * 注意:这里指定使用名称=factory 的 RedisConnectionFactory
     * 并且标识第一个数据源是默认数据源 @Primary
     *
     * @param dataFactory
     * @return
     */
    @Bean("redisDataTemplate")
    @Primary
    public RedisTemplate<String, Object> redisDataTemplate(@Qualifier("dataFactory") RedisConnectionFactory dataFactory) {
        return getRedisDataTemplate(dataFactory);
    }

    //第二个数据源
    @Bean("redisConcurrencyTemplate")
    public RedisTemplate<String, Object> redisConcurrencyTemplate(@Qualifier("concurrencyFactory") RedisConnectionFactory concurrencyFactory) {
        return getRedisConcurrencyTemplate(concurrencyFactory);
    }

    /**
     * 设置序列化方式 (这一步不是必须的)
     *
     * @return
     */
    private RedisTemplate<String, Object> getRedisDataTemplate(RedisConnectionFactory factory) {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //redis 的key 带""号,如"key"
        template.setKeySerializer(jackson2JsonRedisSerializer);
        //redis 的value 不带""号,如"value"
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public RedisTemplate<String, Object> getRedisConcurrencyTemplate(RedisConnectionFactory redisConnectionFactory) {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        //redis 的key 不带""号,如key
        template.setKeySerializer(new StringRedisSerializer());
        //redis 的value 不带""号,如value
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

四、序列化问题

在连接多个redis数据源时,因为我需要取由他人存储的数据,遇到了key和value序列化的问题;

如果序列号方式不对,是取不到数据的。

如果没有该问题getRedisDataTemplate和getRedisConcurrencyTemplate可以合成一个公共方法;

如果遇到这个坑,查看getRedisDataTemplate和getRedisConcurrencyTemplate方法中序列化方式的不同即可。

getRedisDataTemplate在redis中的key带双引号;value也是带的

SpringBoot声明连接多个redis数据源配置模版_redis

getRedisConcurrencyTemplate在rdm中的key不带双引号,value也是不带的;

SpringBoot声明连接多个redis数据源配置模版_spring boot_02


终端取出key,明显看出其差别:

SpringBoot声明连接多个redis数据源配置模版_redis_03

SpringBoot声明连接多个redis数据源配置模版_spring_04

五、封装工具类

1、SpringContextUtil

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public static Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtil.applicationContext = applicationContext;
    }

}

2、RedisLock

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum RedisLock {

    TRANSFER_TASK("transferTask"), MESSAGE_TASK("messageTask"),
    INIT_USERS_TASK("usersTask"), INIT_DEPARTS_TASK("departsTask"), EXTERNALCONTACT_TAG_REMARK("externalcontactTagRemark");
    private String taskName;
}

3、封装第一个RedisDataHelper

import com.data.common.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Set;
import java.util.concurrent.TimeUnit;

@SuppressWarnings("unchecked")
@Slf4j
public class RedisDataHelper {

    private static RedisTemplate<String, Object> redisTemplate = (RedisTemplate) SpringContextUtil.getBean("redisDataTemplate");

    static {
        //处理因为系统异常,key没有被清除的情况
        RedisLock[] values = RedisLock.values();
        for (RedisLock redisLock : values)
            redisTemplate.delete(redisLock.getTaskName());
    }

    public static Boolean hasKey(String redisKey) {
        return redisTemplate.hasKey(redisKey);
    }

    public static <T> T get(String redisKey) {
        return (T) redisTemplate.opsForValue().get(redisKey);
    }

    public static void set(String redisKey, Object value, Long minutesTimeout) {
        redisTemplate.opsForValue().set(redisKey, value, minutesTimeout, TimeUnit.MINUTES);
    }

    public static void set(String redisKey, Object value) {
        redisTemplate.opsForValue().set(redisKey, value);
    }


    public static void set(String redisKey, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(redisKey, value, timeout, unit);
    }

    public static Boolean delete(String redisKey) {
        return redisTemplate.delete(redisKey);
    }

    public static int deleteKeys(String redisKey) {
        Set<String> keys = redisTemplate.keys(redisKey + "*");
        for (String o : keys) {
            redisTemplate.delete(o);
        }
        return keys.size();
    }

    public static <T> T get(String redisKey, Long minutesTimeout, ICallable<T> task) {
        long beginTime = System.currentTimeMillis();
        T obj;
        if (redisTemplate.hasKey(redisKey)) {
            log.info("RedisHelper get redisKey:[{}] times:[{}]ms", redisKey, System.currentTimeMillis() - beginTime);
            obj = (T) redisTemplate.opsForValue().get(redisKey);
        } else {
            obj = task.call();
            redisTemplate.opsForValue().set(redisKey, obj, minutesTimeout, TimeUnit.MINUTES);
            log.info("RedisHelper setRedisKey:[{}] times:[{}]ms", redisKey, System.currentTimeMillis() - beginTime);
        }
        return obj;
    }

    public static void executeWithLock(RedisLock redisLock, Runnable task) {
        String lockKey = redisLock.getTaskName();
        String value = "";
        Boolean isAbsent = redisTemplate.opsForValue().setIfAbsent(lockKey, value);
        if (isAbsent) {
            log.info("{} begin 。。。", lockKey);
            long t1 = System.nanoTime();
            try {
                task.run();
            } catch (Exception e) {
                log.error(lockKey, e);
            } finally {
                long t2 = System.nanoTime();
                final double ms = (t2 - t1) / 1e6d;
                log.info(String.format("%s finished in %.1fms", lockKey, ms));
                //小于10s,做延迟
                if (ms < 10_000) {
                    redisTemplate.opsForValue().set(lockKey, value, 10, TimeUnit.SECONDS);
                    log.info("redisLock {} delay 10s", lockKey);
                } else {
                    redisTemplate.delete(lockKey);
                    log.info("redisLock {} is deleted", lockKey);
                }
            }
        }
    }

    @FunctionalInterface
    public interface ICallable<V> {
        V call();
    }

}

4、封装第二个RedisConcurrencyHelper

import com.data.common.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Set;
import java.util.concurrent.TimeUnit;

@SuppressWarnings("unchecked")
@Slf4j
public class RedisConcurrencyHelper {

    private static RedisTemplate<String, Object> redisTemplate = (RedisTemplate) SpringContextUtil.getBean("redisConcurrencyTemplate");

    static {
        //处理因为系统异常,key没有被清除的情况
        RedisLock[] values = RedisLock.values();
        for (RedisLock redisLock : values)
            redisTemplate.delete(redisLock.getTaskName());
    }

    public static <T> T get(String redisKey) {
        return (T) redisTemplate.opsForValue().get(redisKey);
    }
    public static void set(String redisKey, Object value, Long minutesTimeout) {
        redisTemplate.opsForValue().set(redisKey, value, minutesTimeout, TimeUnit.MINUTES);
    }
    public static void addSet(String key,String value,Double score){
        redisTemplate.opsForZSet().add(key,value,score);
    }
    public static Set gerZset(String key,int offset,int limit){
        return redisTemplate.opsForZSet().range(key, offset, limit);
    }

    public static Set zrangBySocre(String key,double min,double max,int offset,int limit){
        return redisTemplate.opsForZSet().rangeByScore(key,min,max,offset,limit);
    }

    @FunctionalInterface
    public interface ICallable<V> {
        V call();
    }

}


标签:SpringBoot,数据源,redis,redisKey,springframework,org,import,public
From: https://blog.51cto.com/u_16125162/6330109

相关文章

  • Redis常见场景问题和解决方案
    缓存穿透(查不到数据)概述当用户想要查询一个数据,发现Redis中不存在,也就是所谓的缓存没有命中,于是这个数据请求就会打到数据库中。结果数据库中也不存在这条数据,那么结果就是什么都没查询出来。那么当用户很多时候的查询,缓存中都没有数据,请求直接打到数据库中,这样就会给数据库造成很......
  • Redis主从复制实现与原理
    一、概述主从复制,是指将一台Redis服务器的数据复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower);数据是从主节点复制到从节点的。其中,主节点负责写数据(当然有读的权限),从节点负责读数据(它没有写数据的权限)。默认的配置下,每个Redis都是主节点。一......
  • 如何利用Redis进行事务处理呢?
    一、概述事务的本质,其实就是一组命令的集合。一个事务中的所有命令都会按照命令的顺序去执行,而中间不会被其他命令加塞。Redis提供了事务相关的5个指令,分别是:DISCARD、EXEC、MULTI、UNWATCH和WATCH。如下图所示:下面我们就对Redis的事务操作一一的进行介绍。二、MULTI(v1.2.0)指令格式......
  • redis,缓存雪崩,缓存穿透,缓存更新,缓存降级,缓存预热等问题
    一、缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成......
  • 【面试系列6】Redis
    redisredis是什么?内存数据库,一切数据操作都在内存中进行,所以速度很快,常被用来做缓存,消息队列,分布式锁。具有高效的数据结构,String、list、hash、set、zset,bitmaps、hyperloglog、geo、stream。redis还支持事务、持久化、多种集群方式、发布订阅模型、内存淘汰机制等等。re......
  • 微信小程序集成微信支付开发,后端是springboot项目
    一、准备工作首先是进入到小程序后台关联微信支付商户、以及接入微信支付申请 二、小程序端代码主要是用到了wx.requestPaymentAPI2.1在wxml文件中添加支付按钮<buttonbindtap="requestPayment">支付</button>2.2在wxss文件中定义支付按钮样式button{backgro......
  • SpringBoot配置文件
    概述初始化SpringBoot项目时,在resources目录下有一个默认的全局配置文件application.properties。SpringBoot通过配置文件来修改SpringBoot自动配置的默认值SpringBoot支持两种格式的配置文件application.yml和application.propertiesapplication.properties写法appl......
  • idea 中springboot同一服务启动不同端口号
    编辑服务配置2.copy原服务配置一份指定对应端口号启动服务......
  • 基于JAVA的springboot+vue“智慧食堂”设计与实现,食堂管理系统,附源码+数据库+lw文档+P
    1、项目介绍本系统的用户可分为用户模块和管理员模块两大界面组成。一个界面用于管理员登录,管理员可以管理系统内所有功能,主要有首页,个人中心,用户管理,菜品分类管理,菜品信息管理,留言板管理,系统管理,订单管理等功能;另一界面用于用户登录,用户进入系统可以实现首页,菜品信息,留言板,个人......
  • 关于springboot上传完文件读取时资源目录未更新的情况
    之前在实现教学视频上传功能的时候碰到了一个问题,那就是每上传完一个视频文件,页面找不到对应的路径,必须重新构建项目才能找到相应的文件今天在课堂上向老师咨询,才明白javaweb项目读取资源并不是读取实际的本地资源,而是读取target对应目录下的,每个项目都会生成一个对象的target目......