SpringBoot2.1 Redis多數據源集成

在redis中绿渣,一個實例,默認有16個庫燕耿,數據庫名以序號命名0~15中符,可以根據業(yè)務需要的不同,把數據存儲在不同序號的數據中誉帅。在實際應用中淀散,該如何寫配置文件,才能連接多個redis數據源呢蚜锨,今天就來試一試档插。

在使用Redis之前,首先需要安裝Redis數據庫亚再,沒安裝的可以參考SpringBoot初次集成Redis踩坑郭膛,安裝+使用 一文,這里就不細說Redis的安裝了氛悬。

本文基于SpringBoot2.1.4對Redis多數據源進行集成的则剃。在集成的過程中用到了jedis client、Apache的commons-pool2如捅、jackson-databind棍现,以及spring-boot-starter-data-redis,在pom中需要把這些必須的架包引入镜遣;

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

第二步己肮,配置文件的配置;

import java.io.Serializable;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
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.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.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * redis配置類
 * @author 程就人生
 * @date 2019年12月16日
 */
@Configuration
@EnableCaching//開啟注解式緩存
public class RedisMoreDatasourceConfig extends CachingConfigurerSupport {
 
    /**
     * 配置lettuce連接池(多數據源的公共參數)
     * GenericObjectPoolConfig不是線程安全的
     * @return
     */
    @SuppressWarnings("rawtypes")
    @Bean
    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
    public GenericObjectPoolConfig redisPool() {
        return new GenericObjectPoolConfig<>();
    }

    /**
     * 配置第一個數據源的
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.redis")
    public RedisStandaloneConfiguration redisConfig() {
        return new RedisStandaloneConfiguration();
    }

    /**
     * 配置第二個數據源
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.redis2")
    public RedisStandaloneConfiguration redisConfig2() {
        return new RedisStandaloneConfiguration();
    }

    /**
     * 配置第一個數據源的連接工廠
     * 這里注意:需要添加@Primary 指定bean的名稱,目的是為了創(chuàng)建兩個不同名稱的LettuceConnectionFactory
     *
     * @param config
     * @param redisConfig
     * @return
     */
    @SuppressWarnings("rawtypes")
    @Bean("factory")
    @Primary
    public LettuceConnectionFactory factory(GenericObjectPoolConfig config, RedisStandaloneConfiguration redisConfig) {
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        return new LettuceConnectionFactory(redisConfig, clientConfiguration);
    }

    @SuppressWarnings("rawtypes")
    @Bean("factory2")
    public LettuceConnectionFactory factory2(GenericObjectPoolConfig config, RedisStandaloneConfiguration redisConfig2) {
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        return new LettuceConnectionFactory(redisConfig2, clientConfiguration);
    }

    /**
     * 配置第一個數據源的RedisTemplate
     * 注意:這里指定使用名稱=factory 的 RedisConnectionFactory
     * 并且標識第一個數據源是默認數據源 @Primary
     *
     * @param factory
     * @return
     */
    @Bean("redisTemplate")
    @Primary
    public RedisTemplate<Serializable, Serializable> redisTemplate(@Qualifier("factory") RedisConnectionFactory factory) {
        
        RedisTemplate<Serializable, Serializable> template = new RedisTemplate<>();
      
        template.setConnectionFactory(factory);
    
        //使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
          
        template.setValueSerializer(new JdkSerializationRedisSerializer());
          
        template.setHashKeySerializer(new StringRedisSerializer());
          
        template.setHashValueSerializer(new JdkSerializationRedisSerializer());
        
        //開啟事務
        template.setEnableTransactionSupport(true);
          
        template.afterPropertiesSet();
        
        return template;
    }

    /**
     * 配置第一個數據源的RedisTemplate
     * 注意:這里指定使用名稱=factory2 的 RedisConnectionFactory
     *
     * @param factory2
     * @return
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean("redisTemplate2")
    public RedisTemplate<String, Object> redisTemplate2(@Qualifier("factory2") RedisConnectionFactory factory2) {
        
         RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
         
         template.setConnectionFactory(factory2);
         
         Jackson2JsonRedisSerializer 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);
         
         StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
         
         // key采用String的序列化方式
         template.setKeySerializer(stringRedisSerializer);
         
         // hash的key也采用String的序列化方式
         template.setHashKeySerializer(stringRedisSerializer);
         
         // value序列化方式采用jackson
         template.setValueSerializer(jackson2JsonRedisSerializer);
         
         // hash的value序列化方式采用jackson
         template.setHashValueSerializer(jackson2JsonRedisSerializer);
         
         template.afterPropertiesSet();
         
         return template;
    }
}

第三步朴肺,properties文件里也需要對應的參數窖剑;

#Redis common param
spring.redis.lettuce.pool.max-idle=100
spring.redis.lettuce.pool.min-idle=50
spring.redis.lettuce.pool.max-wait=2000

cache.default-exp=72
#data 0
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=3000

#data 1
spring.redis2.database=1
spring.redis2.host=127.0.0.1
spring.redis2.port=6379
spring.redis2.password=
spring.redis2.timeout=3000

第四步,測試代碼戈稿;

import com.alibaba.fastjson.JSONObject;

@RestController
public class IndexController {

    /**
     * 第一個數據源對應的template
     */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    /**
     * 第二個數據源對應的template
     */
    @Autowired
    @Qualifier("redisTemplate2")
    private RedisTemplate<String, Object> redisTemplate2;
    
    //測試
    @GetMapping("/index")
    public void index(){
        
        //數據庫0西土,數據的存儲及取出
        redisTemplate.opsForValue().set("aa", "aaaaa");     
        String aa = (String) redisTemplate.opsForValue().get("aa");     
        System.out.println(aa);
        
        //數據庫1,數據的存儲及取出
        JSONObject json = new JSONObject();
        json.put("aa", "bbbbbb");
        redisTemplate2.opsForHash().put("cc", "aa", json);  
        json = (JSONObject) redisTemplate2.opsForHash().get("cc", "aa");    
        System.out.println(json.toJSONString());
    }
}

最后鞍盗,測試需了;啟動入口程序,在瀏覽器上輸出Controller的地址般甲,從控制臺可以看到測試的結果肋乍;

為了保險起見,還是去客戶端查看一下存儲的結果吧敷存。


在做這個demo時墓造,遇到了一些問題及總結;

  1. 把配置文件的類名命名為RedisConfig锚烦,在項目啟動時會報bean名重復觅闽,這是因為和配置文件里的bean名重復了,這是需要注意的地方涮俄;
  2. 在RedisStandaloneConfiguration類中蛉拙,默認的host是localhost,port是6379彻亲,database默認的是0孕锄,password默認無,這些都可以通過RedisStandaloneConfiguration的源碼找到苞尝,在配置文件里沒有時畸肆,就會使用默認的參數;
  3. 在RedisConnectionFactory接口里宙址,getConnection()有兩種實現方式轴脐,一種是JedisConnectionFactory,一種是LettuceConnectionFactory曼氛,本文的示例中使用的是后一種豁辉,這個可以根據個人喜好進行選擇令野;
  4. 不管有幾個數據源舀患,最好配置一個@Primary數據源;在使用RedisTemplate時气破,如果不用@Qualifier注解指明聊浅,則使用默認的數據源。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市低匙,隨后出現的幾起案子旷痕,更是在濱河造成了極大的恐慌,老刑警劉巖顽冶,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欺抗,死亡現場離奇詭異,居然都是意外死亡强重,警方通過查閱死者的電腦和手機绞呈,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來间景,“玉大人佃声,你說我怎么就攤上這事√纫” “怎么了圾亏?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長封拧。 經常有香客問我志鹃,道長,這世上最難降的妖魔是什么哮缺? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任弄跌,我火速辦了婚禮,結果婚禮上尝苇,老公的妹妹穿的比我還像新娘铛只。我一直安慰自己,他們只是感情好糠溜,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布淳玩。 她就那樣靜靜地躺著,像睡著了一般非竿。 火紅的嫁衣襯著肌膚如雪蜕着。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天红柱,我揣著相機與錄音承匣,去河邊找鬼。 笑死锤悄,一個胖子當著我的面吹牛韧骗,可吹牛的內容都是我干的。 我是一名探鬼主播零聚,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼袍暴,長吁一口氣:“原來是場噩夢啊……” “哼些侍!你這毒婦竟也來了?” 一聲冷哼從身側響起政模,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岗宣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淋样,有當地人在樹林里發(fā)現了一具尸體耗式,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年趁猴,在試婚紗的時候發(fā)現自己被綠了纽什。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡躲叼,死狀恐怖芦缰,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情枫慷,我是刑警寧澤让蕾,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站或听,受9級特大地震影響探孝,放射性物質發(fā)生泄漏。R本人自食惡果不足惜誉裆,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一顿颅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧足丢,春花似錦粱腻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至耀鸦,卻和暖如春柬批,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袖订。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工氮帐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人洛姑。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓上沐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吏口。 傳聞我的和親對象是個殘疾皇子奄容,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354