spring boot:使用多个redis数据源(spring boot 2.3.1)
一,什么情况下需要使用多个redis数据源?
为了缓存数据,通常我们会在线上使用多个redis的cluster,
每个cluster中缓存不同的数据,以方便管理.
例如:我们缓存了杂志文章/商品信息/分类页面
同时我们又使用一个redis cluster作为分布式session
这里就会有多个redis数据源在项目中
说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,演示项目说明:
1,项目地址:
- https://github.com/liuhongdi/multiredissource
2, 项目原理
存储session使用redis集群,
另外使用两个redis实例做缓存
关于redis集群的搭建请参见:
- https://www.cnblogs.com/architectforest/p/13196749.html
3, 项目结构:
如图:
三,项目配置文件说明:
application.properties
- #default redis,for session
spring.redis.cluster.nodes=172.17.0.2:6379,172.17.0.3:6379,172.17.0.4:6379,172.17.0.5:6379,172.17.0.6:6379,172.17.0.7:6379- spring.redis.cluster.max-redirects=3
- spring.redis.password=lhddemo
- spring.redis.database=0
- spring.session.store-type=redis
- spring.redis.lettuce.pool.max-active=8
- spring.redis.lettuce.pool.max-wait=1
- spring.redis.lettuce.pool.max-idle=8
- spring.redis.lettuce.pool.min-idle=0
- #redis1
- spring.redis1.host=127.0.0.1
- spring.redis1.port=6379
- spring.redis1.password=lhddemo
- spring.redis1.database=0
- spring.redis1.lettuce.pool.max-active=8
- spring.redis1.lettuce.pool.max-wait=1
- spring.redis1.lettuce.pool.max-idle=8
- spring.redis1.lettuce.pool.min-idle=0
- #redis2
- spring.redis2.host=127.0.0.1
- spring.redis2.port=6380
- spring.redis2.password=lhddemo
- spring.redis2.database=0
- spring.redis2.lettuce.pool.max-active=8
- spring.redis2.lettuce.pool.max-wait=1
- spring.redis2.lettuce.pool.max-idle=8
- spring.redis2.lettuce.pool.min-idle=0
说明:共3个redis,
存储session的集群有6个节点(3主3从):
172.17.0.2:6379,
172.17.0.3:6379,
172.17.0.4:6379,
172.17.0.5:6379,
172.17.0.6:6379,
172.17.0.7:6379
redis1是非集群结点:
127.0.0.1:6379
redis2是非集群结点:
127.0.0.1:6380
四,java代码说明
1,RedisConfig.java
- @Configuration
- public class RedisConfig {
- @Bean
- @Primary
- public LettuceConnectionFactory redissessionLettuceConnectionFactory(RedisClusterConfiguration redisSessionRedisConfig,
- GenericObjectPoolConfig redisSessionPoolConfig) {
- LettuceClientConfiguration clientConfig =
- LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
- .poolConfig(redisSessionPoolConfig).build();
- return new LettuceConnectionFactory(redisSessionRedisConfig, clientConfig);
- }
- @Bean
- public RedisTemplate<String, String> redisSessionTemplate(
- @Qualifier("redissessionLettuceConnectionFactory") LettuceConnectionFactory redissessionLettuceConnectionFactory) {
- RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
- redisTemplate.setKeySerializer(new StringRedisSerializer());
- redisTemplate.setValueSerializer(new StringRedisSerializer());
- //使用StringRedisSerializer来序列化和反序列化redis的ke
- redisTemplate.setHashKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashValueSerializer(new StringRedisSerializer());
- //开启事务
- redisTemplate.setEnableTransactionSupport(true);
- redisTemplate.setConnectionFactory(redissessionLettuceConnectionFactory);
- redisTemplate.afterPropertiesSet();
- return redisTemplate;
- }
- @Bean
- @ConditionalOnBean(name = "redis1RedisConfig")
- public LettuceConnectionFactory redis1LettuceConnectionFactory(RedisStandaloneConfiguration redis1RedisConfig,
- GenericObjectPoolConfig redis1PoolConfig) {
- LettuceClientConfiguration clientConfig =
- LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
- .poolConfig(redis1PoolConfig).build();
- return new LettuceConnectionFactory(redis1RedisConfig, clientConfig);
- }
- @Bean
- public RedisTemplate<String, String> redis1Template(
- @Qualifier("redis1LettuceConnectionFactory") LettuceConnectionFactory redis1LettuceConnectionFactory) {
- RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
- redisTemplate.setKeySerializer(new StringRedisSerializer());
- redisTemplate.setValueSerializer(new StringRedisSerializer());
- //使用StringRedisSerializer来序列化和反序列化redis的ke
- redisTemplate.setHashKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashValueSerializer(new StringRedisSerializer());
- //开启事务
- redisTemplate.setEnableTransactionSupport(true);
- redisTemplate.setConnectionFactory(redis1LettuceConnectionFactory);
- redisTemplate.afterPropertiesSet();
- return redisTemplate;
- }
- @Bean
- @ConditionalOnBean(name = "redis2RedisConfig")
- public LettuceConnectionFactory redis2LettuceConnectionFactory(RedisStandaloneConfiguration redis2RedisConfig,
- GenericObjectPoolConfig redis2PoolConfig) {
- LettuceClientConfiguration clientConfig =
- LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
- .poolConfig(redis2PoolConfig).build();
- return new LettuceConnectionFactory(redis2RedisConfig, clientConfig);
- }
- @Bean
- @ConditionalOnBean(name = "redis2LettuceConnectionFactory")
- public RedisTemplate<String, String> redis2Template(
- @Qualifier("redis2LettuceConnectionFactory") LettuceConnectionFactory redis2LettuceConnectionFactory) {
- RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
- redisTemplate.setValueSerializer(new StringRedisSerializer());
- redisTemplate.setHashValueSerializer(new StringRedisSerializer());
- //使用StringRedisSerializer来序列化和反序列化redis的ke
- redisTemplate.setKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashKeySerializer(new StringRedisSerializer());
- //开启事务
- redisTemplate.setEnableTransactionSupport(true);
- redisTemplate.setConnectionFactory(redis2LettuceConnectionFactory);
- redisTemplate.afterPropertiesSet();
- return redisTemplate;
- }
- @Configuration
- public static class RedisSessionConfig {
- @Value("${spring.redis.cluster.nodes}")
- private String nodes;
- @Value("${spring.redis.cluster.max-redirects}")
- private Integer maxRedirects;
- @Value("${spring.redis.password}")
- private String password;
- @Value("${spring.redis.database}")
- private Integer database;
- @Value("${spring.redis.lettuce.pool.max-active}")
- private Integer maxActive;
- @Value("${spring.redis.lettuce.pool.max-idle}")
- private Integer maxIdle;
- @Value("${spring.redis.lettuce.pool.max-wait}")
- private Long maxWait;
- @Value("${spring.redis.lettuce.pool.min-idle}")
- private Integer minIdle;
- @Bean
- public GenericObjectPoolConfig redisSessionPoolConfig() {
- GenericObjectPoolConfig config = new GenericObjectPoolConfig();
- config.setMaxTotal(maxActive);
- config.setMaxIdle(maxIdle);
- config.setMinIdle(minIdle);
- config.setMaxWaitMillis(maxWait);
- return config;
- }
- @Bean
- public RedisClusterConfiguration redisSessionRedisConfig() {
- RedisClusterConfiguration config = new RedisClusterConfiguration();
- String[] sub = nodes.split(",");
- List<RedisNode> nodeList = new ArrayList<>(sub.length);
- String[] tmp;
- for (String s : sub) {
- tmp = s.split(":");
- nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
- }
- config.setClusterNodes(nodeList);
- config.setMaxRedirects(maxRedirects);
- config.setPassword(RedisPassword.of(password));
- return config;
- }
- }
- @Configuration
- public static class Redis1Config {
- @Value("${spring.redis1.host}")
- private String host;
- @Value("${spring.redis1.port}")
- private Integer port;
- @Value("${spring.redis1.password}")
- private String password;
- @Value("${spring.redis1.database}")
- private Integer database;
- @Value("${spring.redis1.lettuce.pool.max-active}")
- private Integer maxActive;
- @Value("${spring.redis1.lettuce.pool.max-idle}")
- private Integer maxIdle;
- @Value("${spring.redis1.lettuce.pool.max-wait}")
- private Long maxWait;
- @Value("${spring.redis1.lettuce.pool.min-idle}")
- private Integer minIdle;
- @Bean
- public GenericObjectPoolConfig redis1PoolConfig() {
- GenericObjectPoolConfig config = new GenericObjectPoolConfig();
- config.setMaxTotal(maxActive);
- config.setMaxIdle(maxIdle);
- config.setMinIdle(minIdle);
- config.setMaxWaitMillis(maxWait);
- return config;
- }
- @Bean
- public RedisStandaloneConfiguration redis1RedisConfig() {
- RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
- config.setHostName(host);
- config.setPassword(RedisPassword.of(password));
- config.setPort(port);
- config.setDatabase(database);
- return config;
- }
- }
- @Configuration
- @ConditionalOnProperty(name = "host", prefix = "spring.redis2")
- public static class Redis2Config {
- @Value("${spring.redis2.host}")
- private String host;
- @Value("${spring.redis2.port}")
- private Integer port;
- @Value("${spring.redis2.password}")
- private String password;
- @Value("${spring.redis2.database}")
- private Integer database;
- @Value("${spring.redis2.lettuce.pool.max-active}")
- private Integer maxActive;
- @Value("${spring.redis2.lettuce.pool.max-idle}")
- private Integer maxIdle;
- @Value("${spring.redis2.lettuce.pool.max-wait}")
- private Long maxWait;
- @Value("${spring.redis2.lettuce.pool.min-idle}")
- private Integer minIdle;
- @Bean
- public GenericObjectPoolConfig redis2PoolConfig() {
- GenericObjectPoolConfig config = new GenericObjectPoolConfig();
- config.setMaxTotal(maxActive);
- config.setMaxIdle(maxIdle);
- config.setMinIdle(minIdle);
- config.setMaxWaitMillis(maxWait);
- return config;
- }
- @Bean
- public RedisStandaloneConfiguration redis2RedisConfig() {
- RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
- config.setHostName(host);
- config.setPassword(RedisPassword.of(password));
- config.setPort(port);
- config.setDatabase(database);
- return config;
- }
- }
- }
说明:
分别构造了三个redisTemplate:
redisSessionTemplate:访问redis session cluster
redis1Template:访问redis1
redis2Template:访问redis2
因为要供session默认使用,
所以给第一个LettuceConnectionFactory加上@Primary注解
cluster的配置要使用RedisClusterConfiguration类,
注意与:RedisStandaloneConfiguration区分
2,CacheController.java
- @RestController
- @RequestMapping("/cache")
- public class CacheController {
- @Resource
- RedisTemplate<String, String> redis1Template;
- @Resource
- RedisTemplate<String, String> redis2Template;
- /*
- * get redis1 cache
- */
- @RequestMapping("/redis1get")
- public String redis1Get(HttpServletRequest request){
- String goodsname = redis1Template.opsForValue().get("goodsname1");
- return goodsname;
- }
- /*
- * write redis1 cache
- */
- @RequestMapping("/redis1set/{name}")
- public String redis1Set(@PathVariable String name) {
- //request.getSession().setAttribute("goods", name);
- redis1Template.opsForValue().set("goodsname1",name);
- return "ok";
- }
- /*
- * get redis2 cache
- * */
- @RequestMapping("/redis2get")
- public String redis2Get(HttpServletRequest request){
- String goodsname2 = redis2Template.opsForValue().get("goodsname2");
- return goodsname2;
- }
- /*
- * write redis2 cache
- * */
- @RequestMapping("/redis2set/{name}")
- public String redis2Set(@PathVariable String name) {
- //request.getSession().setAttribute("goods", name);
- redis2Template.opsForValue().set("goodsname2",name);
- return "ok";
- }
- }
说明:对redis1和redis2分别读取和写入
3,SessionController.java
- @RestController
- @RequestMapping("/session")
- public class SessionController {
- /*
- * read session
- * */
- @RequestMapping("/get")
- public Object getSession(HttpServletRequest request){
- Map<String, Object> map = new HashMap<>();
- map.put("sessionId", request.getSession().getId());
- map.put("user", request.getSession().getAttribute("user"));
- map.put("maxInactiveInterval", request.getSession().getMaxInactiveInterval());
- //map.put("ttl", request.getSession().);
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- String time = sdf.format(new Date(request.getSession().getCreationTime()));
- map.put("creationTime", time);
- return map;
- }
- /*
- * write session
- * */
- @RequestMapping("/set/{name}")
- public String setSession(@PathVariable String name, HttpServletRequest request) {
- request.getSession().setAttribute("user", name);
- return "ok";
- }
- }
说明:对session的读取和写入
五,多redis数据源效果测试
1,查看三个redis的数据:
redissession
- [root@redis4 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -a lhddemo -c --cluster call 172.17.0.2:6379 keys \*
- Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
- >>> Calling keys *
- 172.17.0.2:6379:
- 172.17.0.4:6379:
- 172.17.0.3:6379:
- 172.17.0.6:6379:
- 172.17.0.7:6379:
- 172.17.0.5:6379:
redis1:
- 127.0.0.1:6379> keys *
- (empty list or set)
redis2:
- 127.0.0.1:6380> keys *
- (empty list or set)
2,测试session:
访问:http://127.0.0.1:8080/session/set/thislaoliu
设置一个session值为thislaoliu:
访问:http://127.0.0.1:8080/session/get
查询我们设置的session值是否生效?
从redis的控制台检查写入情况:
- [root@redis4 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -a lhddemo -c --cluster call 172.17.0.2:6379 keys \*
- Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
- >>> Calling keys *
- 172.17.0.2:6379: spring:session:sessions:expires:97a889f8-7122-4248-a5fc-4e559cb429e5
- 172.17.0.4:6379: spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
- 172.17.0.3:6379: spring:session:expirations:1593321720000
- 172.17.0.6:6379: spring:session:sessions:expires:97a889f8-7122-4248-a5fc-4e559cb429e5
- 172.17.0.7:6379: spring:session:expirations:1593321720000
- 172.17.0.5:6379: spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
我们连接到172.17.0.4,查询session的值:
- [root@redis3 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -c -h 172.17.0.4
看session的内容:
- 172.17.0.4:6379> hgetall spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
- 1) "sessionAttr:user"
- 2) "\xac\xed\x00\x05t\x00\nthislaoliu"
- 3) "creationTime"
- 4) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01r\xf9CW\xb7"
- 5) "maxInactiveInterval"
- 6) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b"
- 7) "lastAccessedTime"
- 8) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01r\xf9D)n"
可以看到user的值是我们所设置的:thislaoliu
3,测试redis1
访问:http://127.0.0.1:8080/cache/redis1set/cup1
设置一个key,值为:cup1
访问:http://127.0.0.1:8080/cache/redis1get
返回我们设置的值:
连接到redis控制台:
- [liuhongdi@localhost ~]$ /usr/local/soft/redis/bin/redis-cli
从redis控制台查看kv
- 127.0.0.1:6379> get goodsname1
- "cup1"
4,测试redis2
访问:http://127.0.0.1:8080/cache/redis2set/phone1
设置一个key,值为:phone1
访问:http://127.0.0.1:8080/cache/redis2get
返回我们设置的值:
连接到redis控制台
- [root@localhost etc]# /usr/local/soft/redis/bin/redis-cli -p 6380
从控制台查看值
- 127.0.0.1:6380> get goodsname2
- "phone1"
六,查看spring boot的版本
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.3.1.RELEASE)
spring boot:使用多个redis数据源(spring boot 2.3.1)的更多相关文章
- Spring boot配置多个Redis数据源操作实例
原文:https://www.jianshu.com/p/c79b65b253fa Spring boot配置多个Redis数据源操作实例 在SpringBoot是项目中整合了两个Redis的操作实例 ...
- Spring Boot 集成Mybatis实现多数据源
静态的方式 我们以两套配置方式为例,在项目中有两套配置文件,两套mapper,两套SqlSessionFactory,各自处理各自的业务,这个两套mapper都可以进行增删改查的操作,在这两个主MYS ...
- spring boot 基础篇 -- 阿里多数据源
这块是比较基础的配置,阿里数据库配置还是比较好用的,并且可以用来监控数据源的情况.废话不多说,下面看代码. 基于maven项目,在pom.xml中添加引用: <dependency> &l ...
- Spring Boot WebFlux-06——WebFlux 整合 Redis
第06课:WebFlux 整合 Redis 前言 上一篇内容讲了如何整合 MongoDB,这里继续讲如何操作 Redis 这个数据源,那什么是 Reids? Redis 是一个高性能的 key-val ...
- Spring Boot 学习笔记--整合Redis
1.新建Spring Boot项目 添加spring-boot-starter-data-redis依赖 <dependency> <groupId>org.springfra ...
- spring boot 中 Mybatis plus 多数据源的配置方法
最近在学习spring boot,发现在jar包依赖方面做很少的工作量就可以了,对于数据库操作,我用的比较多的是mybatis plus,在中央仓库已经有mybatis-plus的插件了,对于单数据源 ...
- Spring Boot 2.x整合Redis
最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...
- Spring Boot HikariCP 一 ——集成多数据源
其实这里介绍的东西主要是参考的另外一篇文章,数据库读写分离的. 参考文章就把链接贴出来,里面有那位的代码,简单明了https://gitee.com/comven/dynamic-datasource ...
- Spring Boot + Mybatis多数据源和动态数据源配置
文章转自 https://blog.csdn.net/neosmith/article/details/61202084 网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种 ...
随机推荐
- adb安装apk包提示protocol failure问题
截图来自CSDN,待验证
- 吴恩达《深度学习》-第一门课 (Neural Networks and Deep Learning)-第三周:浅层神经网络(Shallow neural networks) -课程笔记
第三周:浅层神经网络(Shallow neural networks) 3.1 神经网络概述(Neural Network Overview) 使用符号$ ^{[
- Linux 获取屏幕分辨率与窗口行列数(c/c++)
获取当前分辨率 #include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<s ...
- 小BUG大原理 | 第一篇:重写WebMvcConfigurationSupport后SpringBoot自动配置失效
一.背景 公司的项目前段时间发版上线后,测试反馈用户的批量删除功能报错.正常情况下看起来应该是个小BUG,可怪就怪在上个版本正常,且此次发版未涉及用户功能的改动.因为这个看似小BUG我了解到不少未知的 ...
- Gradle系列之Android Gradle基础配置
原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...
- 软件工程与UML作业3(互评作业)
博客班级 https://edu.cnblogs.com/campus/fzzcxy/2018SE1/ 作业要求 https://edu.cnblogs.com/campus/fzzcxy/2018S ...
- python中的画笔控制函数
蟒蛇绘制代码中的画笔控制函数 penup() ,pendown() ,pensize() , pencolor()函数 这里就将海龟想象成画笔 画笔控制函数,画笔操作后一直有效,一般成对出现 将画笔抬 ...
- 口罩预约管理系统——系统网站实现(前端+PHP+MySQL)
口罩预约管理系统网站实现 一.前言 二.系统登陆逻辑及界面实现 三.用户模块 1.用户预约系统界面 2.用户查看我的订单界面 3.用户修改预约信息 四.管理员模块 1.管理员登陆界面 2.查看用户预约 ...
- 浅谈 ArrayList 及其扩容机制
浅谈ArrayList ArrayList类又称动态数组,同时实现了Collection和List接口,其内部数据结构由数组实现,因此可对容器内元素实现快速随机访问.但因为ArrayList中插入或删 ...
- Spring AOP系列(一)— 代理模式
Spring AOP系列(一)- 代理模式 AOP(Aspect Oriented Programming)并没有创造或使用新的技术,其底层就是基于代理模式实现.因此我们先来学习一下代理模式. 基本概 ...