Redis 從入門到精通【應(yīng)用篇】之SpringBoot Redis 配置多數(shù)據(jù)源

使用 RedisTemplate 支持多個 Redis 數(shù)據(jù)庫
0. Redis從入門到精通系列文章
- 《Redis 從入門到精通【進(jìn)階篇】之Lua腳本詳解》
- 《Redis 從入門到精通【實踐篇】SpringBoot Redis 配置多數(shù)據(jù)源》
- 《Redis 從入門到精通【進(jìn)階篇】三分鐘了解Redis地理位置數(shù)據(jù)結(jié)構(gòu)GeoHash》
- 《Redis 從入門到精通【進(jìn)階篇】一文學(xué)會Lua腳本》
- 《Redis使用Lua腳本和Redisson來保證庫存扣減中的原子性和一致性》
- 《SpringBoot Redis 使用Lettuce和Jedis配置哨兵模式》
- 《Redis【應(yīng)用篇】之RedisTemplate基本操作》
- 《Redis 從入門到精通【實踐篇】之SpringBoot配置Redis多數(shù)據(jù)源》
- 《Redis 從入門到精通【進(jìn)階篇】之三分鐘了解Redis HyperLogLog 數(shù)據(jù)結(jié)構(gòu)》
- 《Redis 從入門到精通【進(jìn)階篇】之三分鐘了解Redis地理位置數(shù)據(jù)結(jié)構(gòu)GeoHash》
- 《Redis 從入門到精通【進(jìn)階篇】之高可用哨兵機制(Redis Sentinel)詳解》
- 《Redis 從入門到精通【進(jìn)階篇】之redis主從復(fù)制詳解》
- 《Redis 從入門到精通【進(jìn)階篇】之Redis事務(wù)詳解》
- 《Redis從入門到精通【進(jìn)階篇】之對象機制詳解》
- 《Redis從入門到精通【進(jìn)階篇】之消息傳遞發(fā)布訂閱模式詳解》
- 《Redis從入門到精通【進(jìn)階篇】之持久化 AOF詳解》
- 《Redis從入門到精通【進(jìn)階篇】之持久化RDB詳解》
- 《Redis從入門到精通【高階篇】之底層數(shù)據(jù)結(jié)構(gòu)字典(Dictionary)詳解》
- 《Redis從入門到精通【高階篇】之底層數(shù)據(jù)結(jié)構(gòu)快表QuickList詳解》
- 《Redis從入門到精通【高階篇】之底層數(shù)據(jù)結(jié)構(gòu)簡單動態(tài)字符串(SDS)詳解》
- 《Redis從入門到精通【高階篇】之底層數(shù)據(jù)結(jié)構(gòu)壓縮列表(ZipList)詳解》
- 《Redis從入門到精通【進(jìn)階篇】之?dāng)?shù)據(jù)類型Stream詳解和使用示例》
感謝@愛喝茶同學(xué)和其他幾位同學(xué)的問題反饋。對Redis多數(shù)據(jù)源進(jìn)行了改造升級,兼容不同版本和硬編碼配置項的問題,將Jedis 替換為Lettuce, 支持<=Spring boot 2.7.12
1.教程
0. 添加依賴
在項目中使用 RedisTemplate 支持多個 Redis 數(shù)據(jù)庫之前,需要先添加 Spring Data Redis 的依賴。在 Maven 項目中,可以通過在 pom.xml 文件中添加以下依賴來引入 Spring Data Redis:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<spring-boot.version>2.7.12</spring-boot.version>
1. 配置多個 Redis 連接信息
在 Spring Boot 中,可以通過在 application.properties 或 application.yml 文件中指定不同的 Redis 連接信息來配置多個 RedisConnectionFactory 實例,并通過 @Bean 注解將它們注入到 RedisTemplate 中,例如:
Redis的常用配置大概是這些
# Redis 服務(wù)器的主機名或 IP 地址
spring.redis.host=127.0.0.1
# Redis 服務(wù)器的端口號
spring.redis.port=6379
# Redis 服務(wù)器的密碼,如果沒有設(shè)置密碼,則為空字符串
spring.redis.password=
# Redis 數(shù)據(jù)庫的編號,默認(rèn)為 0
spring.redis.database=0
# Redis 服務(wù)器連接超時時間(毫秒),默認(rèn)為 5000 毫秒
spring.redis.timeout=5000
# 連接池最大連接數(shù),即最多允許多少個客戶端同時連接到 Redis 服務(wù)器
spring.redis.pool.max-active=8
# 連接池中最大空閑連接數(shù),即在連接池中最多允許多少個連接處于空閑狀態(tài)
spring.redis.pool.max-idle=8
# 連接池中最小空閑連接數(shù),即在連接池中最少保持多少個連接處于空閑狀態(tài)
spring.redis.pool.min-idle=0
# 連接池最大等待時間(毫秒),即當(dāng)連接池中的連接全部被占用時,新的連接請求最多等待多長時間
# 如果設(shè)置為-1,則表示無限等待
spring.redis.pool.max-wait=-1
# 是否啟用 SSL 加密連接,默認(rèn)為 false
spring.redis.ssl=false
我們將上面的配置改造一下,支持Redis多數(shù)據(jù)源
有同學(xué)反饋之前的寫法有兩方面問題,配置寫死了,新增一個Redis 實例,需要改代碼。還有一個問題是如果沒有排除spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
會報錯
所以本次進(jìn)行修正。將配置支持不限個數(shù)的Redis數(shù)據(jù)源,將Jedis
客戶端改為了lettuce
Spring boot版本升級為<spring-boot.version>2.7.12</spring-boot.version>
# 配置 Redis 數(shù)據(jù)庫 主數(shù)據(jù)源
spring.redis.master.host=172.0.0.1
spring.redis.master.port=6379
spring.redis.master.password=
spring.redis.master.database=15
spring.redis.master.timeout=5000
spring.redis.master.pool.max-active=8
spring.redis.master.pool.max-idle=8
spring.redis.master.pool.min-idle=0
spring.redis.master.pool.max-wait=-1
spring.redis.master.ssl=false
# 配置 Redis 數(shù)據(jù)庫 0
spring.redis.database0.host=172.0.0.1
spring.redis.database0.port=6379
spring.redis.database0.password=
spring.redis.database0.database=0
spring.redis.database0.timeout=5000
spring.redis.database0.pool.max-active=8
spring.redis.database0.pool.max-idle=8
spring.redis.database0.pool.min-idle=0
spring.redis.database0.pool.max-wait=-1
spring.redis.database0.ssl=false
# 配置 Redis 數(shù)據(jù)庫 1
spring.redis.database1.host=172.0.0.1
spring.redis.database1.port=6379
spring.redis.database1.password=
spring.redis.database1.database=1
spring.redis.database1.timeout=5000
spring.redis.database1.pool.max-active=8
spring.redis.database1.pool.max-idle=8
spring.redis.database1.pool.min-idle=0
spring.redis.database1.pool.max-wait=-1
spring.redis.database1.ssl=false
2. 配置
@ConfigurationProperties(prefix = "spring.redis.database0")
和 @ConfigurationProperties(prefix = "spring.redis.database1")
注解來將不同的 Redis 配置注入到 Java 類中,例如:
package com.icepip.project;
import com.alibaba.nacos.common.utils.StringUtils;
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.MutablePropertyValues;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.redis.connection.*;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Configuration
@ConfigurationProperties(prefix = "spring")
public class RedisConfig implements ApplicationContextAware, InitializingBean, BeanPostProcessor {
/**
* 將多個Redis 數(shù)據(jù)源的配置信息放到一個Map中,然后遍歷Map 創(chuàng)建不同的RedisTemplate實例
* Map<String, Map<String, Object>> redis 中的 key 為配置的spring.redis.xx xx為key value xx一組的值組裝成了map
* 創(chuàng)建的RedisTemplate實例的名稱為 xxRedisTemplate
*/
protected static Map<String, Map<String, Object>> redis = new HashMap<>();
// 配置主數(shù)據(jù)源
@Value("${primary.redis.key:master}")
private String primaryKey;
private static ApplicationContext applicationContext;
public RedisConfig() {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
RedisConfig.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
redis.forEach((k, v) -> {
if (Objects.equals(k, this.primaryKey)) {
Map<String, Object> paramMap = new HashMap(4);
v.forEach((k1, v1) -> {
paramMap.put("spring.redis." + k1, v1);
});
MapPropertySource mapPropertySource = new MapPropertySource("redisAutoConfigProperty", paramMap);
((StandardEnvironment) applicationContext.getEnvironment()).getPropertySources().addLast(mapPropertySource);
}
RedisConnectionFactory lettuceConnectionFactory = this.buildLettuceConnectionFactory(k, v, this.buildGenericObjectPoolConfig(k, v));
this.buildRedisTemplate(k, lettuceConnectionFactory);
this.buildStringRedisTemplate(k, lettuceConnectionFactory);
});
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
Map<String, Object> redisParam = redis.get(this.primaryKey);
GenericObjectPoolConfig<?> genericObjectPoolConfig = this.buildGenericObjectPoolConfig(this.primaryKey, redisParam);
RedisConnectionFactory lettuceConnectionFactory = this.buildLettuceConnectionFactory(this.primaryKey, redisParam, genericObjectPoolConfig);
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(lettuceConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate() {
Map<String, Object> redisParam = redis.get(this.primaryKey);
GenericObjectPoolConfig<?> genericObjectPoolConfig = this.buildGenericObjectPoolConfig(this.primaryKey, redisParam);
RedisConnectionFactory lettuceConnectionFactory = this.buildLettuceConnectionFactory(this.primaryKey, redisParam, genericObjectPoolConfig);
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(lettuceConnectionFactory);
return template;
}
private void buildStringRedisTemplate(String k, RedisConnectionFactory lettuceConnectionFactory) {
ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, lettuceConnectionFactory);
this.setCosBean(k + "StringRedisTemplate", StringRedisTemplate.class, constructorArgumentValues);
}
private void buildRedisTemplate(String k, RedisConnectionFactory lettuceConnectionFactory) {
Jackson2JsonRedisSerializer<?> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
Map<String, Object> original = new HashMap<>(2);
original.put("connectionFactory", lettuceConnectionFactory);
original.put("valueSerializer", serializer);
original.put("keySerializer", new StringRedisSerializer());
original.put("hashKeySerializer", new StringRedisSerializer());
original.put("hashValueSerializer", serializer);
this.setBean(k + "RedisTemplate", RedisTemplate.class, original);
}
public GenericObjectPoolConfig<?> buildGenericObjectPoolConfig(String redisKey, Map<String, Object> param) {
GenericObjectPoolConfig<?> result;
if (applicationContext.containsBean(redisKey + "GenericObjectPoolConfig")) {
result = getBean(redisKey + "GenericObjectPoolConfig");
} else {
Map<String, Object> original = new HashMap<>(8);
original.put("maxTotal", param.getOrDefault("maxTotal", 8));
original.put("maxIdle", param.getOrDefault("maxIdle", 8));
original.put("minIdle", param.getOrDefault("minIdle", 0));
original.put("maxWaitMillis", param.getOrDefault("maxWaitMillis", -1L));
original.put("testOnBorrow", param.getOrDefault("testOnBorrow", Boolean.FALSE));
this.setBean(redisKey + "GenericObjectPoolConfig", GenericObjectPoolConfig.class, original);
result = getBean(redisKey + "GenericObjectPoolConfig");
}
return result;
}
public RedisConnectionFactory buildLettuceConnectionFactory(String redisKey, Map<String, Object> param, GenericObjectPoolConfig genericObjectPoolConfig) {
if (!applicationContext.containsBean(redisKey + "redisConnectionFactory")) {
long timeout = Long.parseLong((String) param.getOrDefault("timeout", "3000"));
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(timeout)).poolConfig(genericObjectPoolConfig).build();
RedisConfiguration firstArgument = null;
// 根據(jù)配置項判斷是否是集群或者哨兵或者單機
if (this.isCluster(param)) {
firstArgument = this.buildClusterConfig(param);
} else if (this.isSentinel(param)) {
firstArgument = this.buildSentinelConfig(param);
} else {
firstArgument = this.buildStandaloneConfig(param);
}
ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, firstArgument);
constructorArgumentValues.addIndexedArgumentValue(1, clientConfig);
this.setCosBean(redisKey + "redisConnectionFactory", LettuceConnectionFactory.class, constructorArgumentValues);
}
return getBean(redisKey + "redisConnectionFactory");
}
private RedisStandaloneConfiguration buildStandaloneConfig(Map<String, Object> param) {
RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration();
standaloneConfig.setHostName(String.valueOf(param.get("host")));
standaloneConfig.setDatabase(Integer.parseInt((String) param.get("database")));
standaloneConfig.setPort(Integer.parseInt((String) param.get("port")));
standaloneConfig.setPassword(RedisPassword.of((String) param.get("password")));
return standaloneConfig;
}
private RedisSentinelConfiguration buildSentinelConfig(Map<String, Object> param) {
RedisSentinelConfiguration config = new RedisSentinelConfiguration();
// todo 如果是哨兵模式需要要在此處額外的配置,可以完善
return config;
}
private RedisClusterConfiguration buildClusterConfig(Map<String, Object> param) {
RedisClusterConfiguration config = new RedisClusterConfiguration();
// todo 如果是Cluster模式需要在此處額外的配置,可以完善
return config;
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,請在applicationContext.xml中定義SpringContextUtil");
}
}
public static <T> T getBean(String name) {
checkApplicationContext();
return applicationContext.containsBean(name) ? (T) applicationContext.getBean(name) : null;
}
public synchronized void setBean(String beanName, Class<?> clazz, Map<String, Object> original) {
checkApplicationContext();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
if (!beanFactory.containsBean(beanName)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(clazz);
if (beanName.startsWith(this.primaryKey)) {
definition.setPrimary(true);
}
definition.setPropertyValues(new MutablePropertyValues(original));
beanFactory.registerBeanDefinition(beanName, definition);
}
}
public synchronized void setCosBean(String beanName, Class<?> clazz, ConstructorArgumentValues original) {
checkApplicationContext();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
if (!beanFactory.containsBean(beanName)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(clazz);
if (beanName.startsWith(this.primaryKey)) {
definition.setPrimary(true);
}
definition.setConstructorArgumentValues(new ConstructorArgumentValues(original));
beanFactory.registerBeanDefinition(beanName, definition);
}
}
private boolean isSentinel(Map<String, Object> param) {
String sentinelMaster = (String) param.get("sentinel.master");
String sentinelNodes = (String) param.get("sentinel.nodes");
return StringUtils.isNotEmpty(sentinelMaster) && StringUtils.isNotEmpty(sentinelNodes);
}
private boolean isCluster(Map<String, Object> param) {
String clusterNodes = (String) param.get("cluster.nodes");
return StringUtils.isNotEmpty(clusterNodes);
}
public Map<String, Map<String, Object>> getRedis() {
return redis;
}
}
使用
@ConfigurationProperties(prefix = "spring")
注解將不同的redis Map配置 實例中,并通過動態(tài)構(gòu)造RedisTemplate
實例.并且放置到Spring容器中, 這樣,在代碼中就可以通過@Qualifier
注解來注入不同的RedisTemplate
實例,從而訪問不同的 Redis 數(shù)據(jù)庫。還有同學(xué)反饋 需要有個主Redis 實例,所以又把RedisTemplate 手動構(gòu)造了一份放置容器
3. 使用 RedisTemplate 實例
在 Spring Boot 中,可以通過 @Qualifier
和 @Autowired
注解將不同的 RedisTemplate 實例注入到 Java 類中,例如:
@RestController
public class ConsumerController {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
@Qualifier("database0RedisTemplate")
private RedisTemplate<Object, Object> redisTemplate0;
@Autowired
@Qualifier("database1RedisTemplate")
private RedisTemplate<Object, Object> redisTemplate1;
@Autowired
@Qualifier("database0StringRedisTemplate")
private StringRedisTemplate stringRedisTemplate0;
@Autowired
@Qualifier("database1StringRedisTemplate")
private StringRedisTemplate stringRedisTemplate1;
@GetMapping("/call")
public String call() {
return "call";
}
@GetMapping("/save")
public String save() {
return "save";
}
}
4. 使用 RedisTemplate 操作 Redis
在 RedisTemplate 中,提供了一系列方法來操作 Redis,例如:
// 存儲數(shù)據(jù)到 Redis 數(shù)據(jù)庫 0
redisTemplate0.opsForValue().set("key0", "value0");
// 獲取數(shù)據(jù)從 Redis 數(shù)據(jù)庫 0
Object value0 = redisTemplate0.opsForValue().get("key0");
// 刪除數(shù)據(jù)從 Redis 數(shù)據(jù)庫 0
redisTemplate0.delete("key0");
// 存儲數(shù)據(jù)到 Redis 數(shù)據(jù)庫 1
redisTemplate1.opsForValue().set("key1", "value1");
// 獲取數(shù)據(jù)從 Redis 數(shù)據(jù)庫 1
Object value1 = redisTemplate1.opsForValue().get("key1");
// 刪除數(shù)據(jù)從 Redis 數(shù)據(jù)庫 1
redisTemplate1.delete("key1");
2. 常見問題
按照之前版本在使用 Spring Boot 中的 Redis 進(jìn)行多數(shù)據(jù)源配置時,可能會遇到以下幾個常見問題,新版本應(yīng)該不會遇到,已經(jīng)做了兼容。
2.1. RedisTemplate 實例重名問題
在配置多個 Redis 數(shù)據(jù)庫時,需要為每個 Redis 數(shù)據(jù)庫創(chuàng)建一個 RedisTemplate 實例。如果不同的 RedisTemplate 實例的名稱相同,可能會導(dǎo)致實例重名的問題,進(jìn)而導(dǎo)致應(yīng)用程序無法啟動。為每個 RedisTemplate 實例指定不同的名稱。例如,可以在配置類中通過 @Bean 注解為每個 RedisTemplate 實例指定名稱
@Bean(name = "redisTemplate0")
public RedisTemplate<String, Object> redisTemplate0(RedisConnectionFactory redisConnectionFactory0) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory0);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean(name = "redisTemplate1")
public RedisTemplate<String, Object> redisTemplate1(RedisConnectionFactory redisConnectionFactory1) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory1);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
在上面的代碼中,我們分別為兩個 RedisTemplate 實例指定了不同的名稱,分別為 “redisTemplate0” 和 “redisTemplate1”。
2.2. RedisConnectionFactory 實例重用問題
在配置多個 Redis 數(shù)據(jù)庫時,需要為每個 Redis 數(shù)據(jù)庫創(chuàng)建一個 RedisConnectionFactory 實例。如果多個 RedisConnectionFactory 實例使用了同一個 Redis 連接池,可能會導(dǎo)致實例重用的問題,進(jìn)而導(dǎo)致應(yīng)用程序無法啟動??梢詾槊總€ RedisConnectionFactory 實例配置不同的 Redis 連接池。例如,可以在配置類中創(chuàng)建不同的 RedisConnectionFactory 實例,并分別為它們配置不同的 Redis 連接池
@Bean(name = "redisConnectionFactory0")
public RedisConnectionFactory redisConnectionFactory0() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("localhost");
config.setPort(6379);
config.setPassword(RedisPassword.of("password"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setDatabase(0);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
@Bean(name = "redisConnectionFactory1")
public RedisConnectionFactory redisConnectionFactory1() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("localhost");
config.setPort(6379);
config.setPassword(RedisPassword.of("password"));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setDatabase(1);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
2.3. 數(shù)據(jù)庫編號配置問題
在配置多個 Redis 數(shù)據(jù)庫時,需要為每個 Redis 數(shù)據(jù)庫指定不同的數(shù)據(jù)庫編號。如果多個 Redis 數(shù)據(jù)庫使用了同一個數(shù)據(jù)庫編號,可能會導(dǎo)致數(shù)據(jù)被覆蓋或丟失。為了解決這個問題,可以為每個 RedisConnectionFactory 實例配置不同的數(shù)據(jù)庫編號。例如,可以在 RedisStandaloneConfiguration 中指定不同的數(shù)據(jù)庫編號
@Bean(name = "redisConnectionFactory0")
public RedisConnectionFactory redisConnectionFactory0() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("localhost");
config.setPort(6379);
config.setPassword(RedisPassword.of("password"));
config.setDatabase(0);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
@Bean(name = "redisConnectionFactory1")
public RedisConnectionFactory redisConnectionFactory1() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("localhost");
config.setPort(6379);
config.setPassword(RedisPassword.of("password"));
config.setDatabase(1);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
2.4. RedisTemplate 序列化問題
在使用 RedisTemplate 時,需要對數(shù)據(jù)進(jìn)行序列化和反序列化。如果不同的 Redis 數(shù)據(jù)庫使用了不同的序列化方式,可能會導(dǎo)致數(shù)據(jù)無法正常讀寫。每個 RedisTemplate 實例指定不同的序列化器。例如,可以為每個 RedisTemplate 實例分別設(shè)置不同的 keySerializer 和 valueSerializer 。但是通常情況下我們的的項目中的序列化方式都是一致的,除非是在連別的項目的Redis時候人家已經(jīng)按自己的序列化方式將值已經(jīng)寫入,我們只能按照對接方的方式配置序列化。文章來源:http://www.zghlxwxcb.cn/news/detail-599074.html
@Bean(name = "redisTemplate0")
public RedisTemplate<String, Object> redisTemplate0(RedisConnectionFactory redisConnectionFactory0) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory0);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean(name = "redisTemplate1")
public RedisTemplate<String, Object> redisTemplate1(RedisConnectionFactory redisConnectionFactory1) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory1);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
大家好,我是冰點,今天的Redis【實踐篇】之SpringBoot Redis 配置多數(shù)據(jù)源,全部內(nèi)容就是這些。如果你有疑問或見解可以在評論區(qū)留言。文章來源地址http://www.zghlxwxcb.cn/news/detail-599074.html
到了這里,關(guān)于SpringBoot Redis 配置多數(shù)據(jù)源的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!